Getting started with DSL

Basic rules

While domain specific language used in platform could look like anything, most of the concepts are defined to follow few basic rules:

  • bracket blocks for nesting
  • semicolon statements for concept declarations
  • case sensitive identifiers
  • semi case insensitive keywords

In practice this would look like

module Todo
    Value Message;

where module, AGGREGATE and Value are all valid keywords used to identify type of declared concept written in lowercase, uppercase or first letter uppercase with rest of it lowercase.

Identifiers such as Todo, Task and Message are case sensitive and when referenced in other parts of DSL will be only exactly matched.

Each declaration ends with semicolon ";" for closing the definition of that concept, or with open bracket "{" if nested concepts are to be defined inside it.

When inside block, declared concepts are "aware" of its context and will use it to infer information.

Concept rules

Each concept has its own declaration (or multiple ones). All of them follow simple rules:

  • when possible, declared as concept name concept identifier inside its parent
  • keywords are not restrictive (but underlying platform will impose its own keyword restrictions)
  • they are extended, instead of modified by their children
  • most concepts can be extended after they have been declared

If they need more information to be declared in full, it will probably follow this common declaration. Since DSL is focused on human consumption instead of computer parsing, there are few ambiguities in grammar, which can be resolved with more verbose concept declaration, but will be resolved automatically based on priority.

In practice this would mean that concepts declared in script:

module Test
    value Complex
        int i;

can be extended later by another script:

module Test {
    value Complex {
        int j;

which is the same as writing it all at once:

module Test { value Complex { int i; int j; } }

Special rules


Single and multiple line comments are available, so you can use // or /* and */ to comment out blocks of DSL.

String values and expressions

String values and underlying platform expressions can be written in three ways. Using single or double quotation marks (' and ") or with a special pattern: <# ... #>. This means that concepts such as specification which require lambda expression to declare predicate can will be written as:

module Test {
    value Complex {
        specification IsNormalized 'c => c.i * c.i + c.j * c.i == 1';

This lambda expression will be compiled to underlying platform, so rules of the underlying platform must be satisfied.


When syntax error is found, parser will point to the location in the file where the error was found. Usually those errors are miswritten keyword name, forgotten semicolon and reference to unknown object.

Because of the open world nature of the grammar, sometimes error messages leave something to be desired. In the future we expect much better error messages, but for now this means that you shouldn't write large swaths of grammar without parsing it regularly and fixing errors in it.

Unsafe concepts

Since neither .NET nor JVM track side effects, some concepts which expose platform code are unsafe (such as validation messages, event actions, etc.). Those concepts are not available in test projects, since we are not trying to validate them yet for their side effects.