1. Summary
  2. Files
  3. Support
  4. Report Spam
  5. Create account
  6. Log in

LWC11 Task 0.1

From whole

Jump to: navigation, search

This page is part of the Whole Platform LWC11_Submission.



0.1 Simple (structural) DSL without any fancy expression language or such

Build a simple data definition language to define entities with properties. Properties have a name and a type. It should be possible to use primitive types for properties, as well as other Entities.


Entities 0.1 Grammar


In a model driven approach, a language consists of a single mandatory part: the structure or (meta)model, and zero or more notations, persistences and other (mainly translational) semantics. By taking a domain specific approach, the Whole Platform provides several languages targeted at language definition. Each language is focused on one domain representing an aspect of language definition (i.e. structure, concrete syntax, notation, tooling, generators).

The more straightforward way to define a language in Whole is to define only its structure using the Models DSL and let the Platform provide generic notations and persistences for the new language instances. We will illustrate this solution at the end of this chapter.

Here, we consider as a requirement the ability to parse/unparse the textual syntax used in the LWCTask examples. So, we start defining the grammar of the language using the Grammars DSL and we let the Platform derive the structure and notation.

The two solutions are in fact complementary: we can regard the latter as a way to add a specific textual persistence to a language and conversely we can regard the former as a way to specify the desired structure for a grammar defined language.


Creating a Whole Project

Creating a Whole Project is a fairly straightforward task. From the Eclipse menu bar, select File > New > Whole Project...


In the Project name field, type org.whole.crossexamples.lwc11 and click Finish when you are done.


Eventually, you'll end up with a workspace containing the newly created Whole Project.


A Whole Project it's basically a Java Project configured to include the Whole Platform Library in the build path.

Creating a Grammar Model

The Whole Language Workbench provides several meta-languages that can be used to define new languages. The primary responsibility of a meta-language is to define the abstract syntax of the language being modeled. Meta-languages may also define concrete syntaxes, graphical notations or other language specific features.

It is important to note that the Whole Language Workbench doesn't impose any distinction between languages and meta-languages. A language can be considered implicitly a meta-language by adding the means to define new languages using its own instances. Grammars is such a language, and allows the definition of new languages (both abstract and concrete syntax) using an EBNF like notation.

To create a Grammar model we have to use the New Whole Model wizard, note that throughout this document we will use the term model as a synonym of language instance. But to keep things clean, at first we will create two package. A first package, named org.whole.crossexamples.lwc11, to contain the language meta-models and the associated behavior. The second package, named org.whole.crossexamples.lwc11.examples, to store the provided sample models.

To create a new package, right-click on the src folder and select File > New > Package.


Add both packages using the New Java Package wizard. Eventually, the updated project will contain the newly created packages.


Now we can create a Grammar model by right-clicking on the org.whole.crossexamples.lwc11 package and selecting File > New > Whole Model.


The New Whole Model wizard window allows us to specify several details regarding the model being created. The upper area allows the selection of the containing folder, that we implicitly choose by right-clicking on the destination package. After the destination path we can type EntitiesGrammar.xwl in the File Name field. Finally, we can choose Grammars as the target language with an empty starting template saved using the generic XML (Whole Template Builder) persistence.


A resource named EntitiesGrammar.xwl will be created in the specified folder, and a corresponding Whole Graphical Editor will be opened showing the newly created resource contents.


The graphical editor shows a skeleton grammar that can be customized to fit our needs. Before diving into the required grammar customization steps, it is useful to understand some basic editing principles of the Whole Platform. In the Whole Platform, language constructs are generically referred as Entities. There are four main kinds of entities:

  1. Simple entities represent a list of named features
  2. Composite entities represent collections of entities
  3. Data entities represent data values
  4. Enum entities represent enumerated values

The preferred way of editing a model is the Whole Graphical Editor. Since we are using a graphical editor, all the editing operations are performed using the provided content assist (by using the context menu or the Meta+Space keystroke) or by means of drag'n'drop operations. The set of allowed operations will be restricted by the abstract syntax constraints of the target entity. Other ways to inspect the model's contents are the Outline View (that is always bound to the active editor) and the projection views (i.e. the Details View).

Several notations are provided for every language family, some of them are generic (i.e. available for a family of languages) other are language specific. Some notations may hide parts of the models being edited (often to reduce complexity), but the Outline always shows the entire tree structure. Notations can be changed using the proper context menu item.

In the following screenshot a Whole Graphical Editor is shown in the central pane of the workspace window with the WHITESPACE lexical production being selected. The Outline on and the Details view show the same selected production in different ways.


In the graphical editor depicted above several red and black squares are shown. They are placeholders that can be replaced with concrete language entities. In fact, the red ones must be replaced because they represent mandatory features, while the smaller black ones are optional.

A placeholder figure is shown also on collection figures. While hovering a composite figure, the insertion point is highlighted using an horizontal or vertical narrow line. Both the context menu actions and the drag'n'drop operations use that hint to modify the underlying figure.


Now we are ready to modify our first grammar model. We start defining some features to identify the grammar: the uri (used to uniquely identify grammars inside the platform), the namespace (used as package prefix for artifacts produced by generation actions) and the grammar name. Finally, we have to insert a LanguageDescriptor in the target language feature filled with analogous information to identify the target language to which this grammar is bound.

As we previously said, to replace a placeholder use the content assist. To avoid confusion, in this part of the tutorial simply stick to the Grammars submenu of the content assist menu. To enter text editing mode it's enough to double-click on any editable label, to terminate text editing simply press the carriage return or the escape key. Remove any other entity below the top level pane so that the end result is similar to the figure shown below.


Note that we can have several grammar models bound to a single target language, because the target language defines an abstract syntax while each grammar defines a concrete syntax. Also, if the target language has not been already defined into the Whole Platform, there's a default mechanism to derive it from the grammar model itself.

The next step is to define a delimiter, using a Literal Terminal that consumes whitespace sequences. The delimiter can be used to determine the start and end position of the next token to be consumed.


The literal terminal allows to specify a regular expression used to consume input during a parse operation, and a literal string to produce output during an unparse operation. The parse operation is useful to transform a stream of characters into an in memory model, while the unparse operation produces the opposite effect.

We can now define the first Production inside the phrase structure.


The Name production defines a rule to parse an identifier using a Data Terminal. During the parse operation data terminals behave similarly to literal terminals, but the captured data is stored in memory for later reuse. When the unparse operation is invoked data terminals output the previously stored data using the provided formatter.

It is worth noting that since the Name production contains only a data terminal, it will be mapped to a data entity in the target language. The STRING value next to the production name is used define the data-type of the mapped data entity (this is particularly useful in case we have to derive the target language from the grammar model itself).

The next production we define is called PrimitiveType. Basically, the main rule uses a Choose construct to define the set of alternatives that may be encountered during the parse operation, the values are matched using literal terminals. Since the production matches only literal terminals, it will be mapped to an enum entity in the target language. The As rules are used to explicit the mapping between literals and enum values.


We can now define the Type production as the alternative between the Name and the PrimitiveType rules, note that Grammar models allow arbitrary nesting of productions.


The Entity production uses a Concatenate rule to define the sequence of LiteralTerminals and NonTerminals to be parsed. It has a nested Repeat rule that defines an unbounded collection of properties. Each property will be mapped using its own Property production. Note that a few non consuming whitespace rules (Space, Indent and NewLine) are added to produce a prettier output.


Finally we define the Entities production to be an unbounded collection of entities. Note that the Entities non-terminal is specified as the default starting symbol. The complete grammar is shown below.


Using the Grammar Model

The easiest way to use the grammar model is to deploy it into the Whole Platform. We use the term deploy in several contexts to indicate that we are enriching the runtime with the resource being deployed. In this specific case, we expect to add to the platform the target language derived from the grammar model and the configurations needed to persist such a language using the concrete syntax.

To deploy the grammar model we have to invoke the interpreter operation. The Whole Language Workbench provides a toolbar that allows the user to invoke a set of predefined operations on languages. The workbench enables only the actions that can be executed on the active editor. So make sure that the EntitiesGrammar is the active editor and click on the interpret action, as shown below.


Now we can proceed by creating an example text file to be parsed. Using the New File wizard create an empty file inside the org.whole.crossexamples.lwc11.examples package and name it EntitiesExample.txt. The workbench will open a text editor to modify the newly created file contents. Copy the example provided by The Task in the open editor and save.

entity Person {
    string name
    string firstName
    date birthDate
    Car ownedCar

entity Car {
    string make
    string model


The example entities file can be opened using the already deployed grammar. Right-click the EntitiesExample.txt and select Open With > Grammar Based Persistence.


A new graphical editor showing the entities example content is opened. By dragging the graphical editor's tab on the right side of the editor area, you can put the graphical and textual editors side by side.


Experiment with both the editors by performing changes on one side, and looking at how they are reflected on the other side.

Personal tools