Skip to content

DSLFoundry/mps-lwc25

Repository files navigation

mps-lwc25

This repository contains the JetBrains MPS submission for "The State of the Art in Language Workbenches: 12 years later" paper. It holds a simple implementation (excluding satisfiability checking) of the Questionnaire Language (QL) as described in the original QL assignment.

Authors: Klemens Schindler (@klemensschindler) and Eugen Schindler (@eugenschindler)

The original JetBrains MPS QL implementation is in the repository https://github.com/DSLFoundry/mps-lwc14, which in turn is based on https://github.com/DSLFoundry/mps-lwc13.

Input documentation

The documentation for input to the paper can be found here:

Setup

  • Install JetBrains MPS 2025.1 from the list on https://www.jetbrains.com/mps/download/previous.html for your platform
  • Run ./gradlew (the used MPS and gradle 7 needs java 21) after cloning this repository in order to download all dependencies and build the language
  • Open the root directory of this repository in MPS
  • To play with an example QL model, open the root node QuestionnaireLanguage → Sandbox → Sandbox → QLBasic → HouseOwning

New QL language implementation

This section sketches the language implementation highlights and especially the differences in effort and amount of code needed to implement the language in MPS 2025.1 (and included batteries) as compared to the original last implementation of QL from 2014 in MPS 2.5.

General observations

Since version 2.5, MPS and its ecosystem of commercial and community-based libraries has evolved quite much. Most notably, for the new implementation of QL, we have heavily used the KernelF extensible "funclarative" language (contained within the IETS3.opensource project). In practice, the most frequent use case of KernelF we have encountered, is to just "plug-in" and tailor (advanced) expressions instead of having to develop an expression hierarchy and various useful functionality for it every time from scratch in a language.

Another useful extension is the plaintextgen plugin which helps to easily generate all types of custom text from MPS models. Since we used HTML as generation target, we could also have used the built-in jetbrains.mps.lang.html language to generate the code, but we chose plaintextgen to illustrate a quick and easy method of getting text out of models.

Implementation walkthrough

What stayed the same?

  • Each of the concepts mentioned in the QL assignment has been implemented 1:1 as an MPS concept.
  • Similar as in the original implementation in 2013, we have used the IQuestionBlockContents (now renamed to IFormContents) interface concept to allow for free creation and movements of lines in the structural projectional editor of MPS.
  • The Empty concept represents empty lines. In addition, we have the DerivedValueReference and QuestionReference concepts in order to model references in the language.
  • Since the de.slisson.mps.richtext language already existed to model rich text, we have done this again in the new implementation, since richtext suffices for the text of a question. If we would have had a need for more advanced text modeling (à la LaTeX, including references to other part of the model, tagging, document structure, etc.), we could have used the mbeddr.doc language (with various out-of-the-box generation targets like HTML, Markdown, and LaTeX/PDF).

What was done differently?

  • In order to model the type of a question, we chose to simply hook into the KernelF language, using KernelF's Type concept. This enables us to leverage the KernelF infrastructure of typing. What this does in practice, is that we can simply import the KernelF simpleTypes language (org.iets3.core.expr.simpleTypes) on model-level in order to get a whole set of standard types, such as Boolean, NumberType, and String. The only effort it takes to leverage all this infrastructure, is to simply make the type child of the Question concept of type Type (org.iets3.core.expr.base).
  • Like a Question, a DerivedValue also has a KernelF Type, but in order to derive a value, we also need an expression. Here, we simply make a child called value which is of type Expression (org.iets3.core.expr.base). This gives us access to the full set of expressions possible in KernelF (ranging from simple binary expressions like addition or multiplication, to dot expressions, option types, logic expressions, (in) equalities, etc.). In order to make sure that we connect to the KernelF typesystem, we have to add a type inference rule that makes sure that the type of a DerivedValue.value is equal to the expected type. This makes sure that whatever type computation happens via the KernelF infrastructure, we will get feedback from the editor if the resulting type of the expression in value does not fit with expectedType.
  • In the same way, in order to have advanced conditions for the if-blocks in QL, we just need to make the condition child of the ConditionalBlock concept of type BooleanExpression (org.iets3.core.expr.base).
  • In order to allow for using references to question and derived value definitions in expressions like derived values or conditions of a conditional block, we simply hook these references into KernelF as custom expressions, so they can compose with the KernelF expression machanism. This is accomplished by simply making the QuestionReference and DerivedValueReference concepts extend Expression (org.iets3.core.expr.base).
  • In MPS 2.5 there was no plaintextgen plugin, so we would have been forced to either make a textgen aspect for each concept directly (which is really not fun to do and a lot of work) or to define an intermediate language for HTML (which also didn't yet exist out of the box in MPS 2.5). Using plaintextgen, however, making a code generator quickly for a specific case is as simple as copy-pasting the reference implementation into a plaintextgen model (which models lines, words, and general layouts of plain text) and then simply add generator macros to the relevant parts of the reference implementation in order to templatize the static reference implementation text, which is pretty similar to typical template-driven code generation.

Considerations / downsides

  • Using KernelF's expression infrastructure adds quite some advanced functionality to a language with almost zero effort. If the language is relatively simple, however, one may want to restrict the plethora of possible expressions of KernelF to only a subset (e.g. only additions, subtractions, multiplications, and divisions). Though it doesn't cost much effort, it needs some considerations. Details are beyond the scope of this text.

Other features not touched in this JetBrains MPS QL implementation

  • kotlin base language instead of java base language
  • constraint-based typesystem
  • shadow models or Dclare4MPS (for QL, this can enable a live programming workflow, transforming to generated HTML code incrementally and continuously while editing the model)
  • see the MPS Extensions documentation for an overview of community extensions
  • see MPS Platform Docs for a nearly exhaustive overview of the most used non-commercial third-party MPS extensions
  • the build language itself is a generation target, which makes it possible to build extensions to the MPS build mechanism itself

Conclusions for JetBrains MPS implementation of QL in 2025

In the last 12 years, MPS itself has done steps to further engineer and stabilize the tool. Many bugs have been fixed, existing features streamlined, and performance highly optimized. The basic meta-interfaces of the MPS structure aspect have stayed stable, while many other aspects and additional extension capabilities and features (such as custom aspects, testing and debugging infrastructure for various aspects, mass node manipulation, many productivity features in the IDE, generation plans, ...) have been added.

In addition, commercial and community extensions have been developed that add productivity and power to the toolbox of MPS language developers. This enables a quite concise and powerful way to write and maintain ecosystems of languages and language stacks for people who are knowledgeable with MPS language development, while keeping basic language creation still relatively accessible to new MPS language developers.

Some statistics

  • Total code written: 1023 nodes

    • Language: 256 nodes
    • Generator: 621 nodes
    • Build solution: 106 nodes
    • Example model: 40 nodes
  • Total implementation effort (excluding documentation and build setup, including design): 5 person hours

  • Total documentation effort (README, Summary, Excel sheets): 10 person hours

  • Total coffee consumed: 7 cups

  • Total cookies/candies eaten: 11

  • In the last (mps-lwc14) implementation, the amount of total nodes is a factor of 43 more than the current implementation (mps-lwc25). Let's be generous and say that the SAT checking made the code base twice as complex, then we still come to more than a factor of 21 in size reduction!

  • The last implementation took 5 people several evenings, while the current implementation was 2 people (excluding one cosmetics commit from JetBrains) for 2 short evenings (excluding documentation). We don't have exact statistics to factor out the exact implementation time from the design time, but the significant reduction in amount of total implementation code (measured in nodes), should give a pretty good idea of how much less the implementation work itself was.

In this specific QL implementation, we attribute the high reduction in code (and hence implementation effort) to KernelF (which saves having to make from scratch entire expression concept hierarchies) and plaintextgen (which saves textgens or intermediate languages and drastically reduces the effort of templatizing reference implementations from plain text).

Final statement

With this data, we can conclude that the QL implementation may not be a benchmark to extensively measure the power of language implementation in MPS. It may be time to update the benchmark to a level that is more challenging for MPS and its opensource ecosystem of "batteries included" :-)

About

JetBrains MPS submission for "The State of the Art in Language Workbenches: 12 years later" paper

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors