Up Previous Next Title Page Index Contents

5.3.1 Getting started with MERL

MERL is a scripting language with commands for navigating through design models, extracting information from design elements and outputting it to a window or file. There are also a number of additional utility commands that enable for example various user interventions or execution of external programs. These commands are explained in detail in the following sections, while Section 5.3.9 provides a quick reference to them.

Before learning about the individual commands, let us concentrate first on the basics of MERL. Consider the following example generator definition for the Watch example:
01  Report 'Test'
02  foreach .State [Watch]
03  {  'State : '
04     :State name;
05     newline
06     'Connects to: '
07     newline
08     do ~From>()~To.State [Watch]
09     {  ' 	'
10        :State name;
11        newline
12     }
13     newline
14  }
15  endreport 
This example illustrates the basic features of a generator definition. Generator definitions accessed from the Generator Browser always carry the header token Report and the name of the generator definition (line 1). Similarly, the generator definition is closed by the endreport token (line 15). These header and end tokens, however, are not present in those short generator definitions used in the Symbol Editor or for identifier generators in the Object Tool etc.: since these are not run manually, they do not need a name.

All generators operating on the graph level, like our example here, must access their member elements like objects, relationships, roles and ports within a top-level foreach loop. In the above example (lines 2 – 14), we loop through the instances of the ‘State [Watch]’ object type and retrieve specific information from them to be output. For each state, we want to output its name, followed by a list of the states it is connected to. After the foreach command you will notice the use of the ‘.’ prefix character before the name ‘State [Watch]’. The prefix characters ‘.>~#:’ make the distinction between Objects, Relationships, Roles, Ports and Properties. For example, in line 2 the ‘.’ preceding the type name tells the generator to expect an object as the next retrievable element.

In line 3 we enter the loop: lines 3 – 14 will be executed once for each ‘State [Watch]’ in the graph. Outside the loop we can say that we are ‘in’ the graph; within the loop we can say that we are ‘in’ a ‘State [Watch]’ object.

In lines 3 – 5 we first output the string ‘State : ’, then the value of the ‘State name’ property of the current ‘State [Watch]’ object and then complete the output with a line break. Again, please note the ‘:’ prefix before ‘State name’ that denotes that a property will follow. Lines 6 – 7 simply output the string ‘Connects to: ’ followed by a line break.

As you can see, none of these output commands need specify where the output is going: all output is simply appended to the current output stream. By default, the stream just goes to a window, whose result will be shown to the user at the end of the generation. It is also possible to direct output to files (see Section 5.3.5) or to named internal streams, which can be used as variables (Section 5.3.6). Temporary streams are also used by some commands to form their arguments, e.g. to build up the name of a file to print a bitmap of the current graph to, from the name of the graph plus an extension:
filename  :Application name; '.png'  print
Lines 8 – 12 contain an important example of a very basic feature of MERL: navigation through bindings. In this case, we want to find out all other ‘State [Watch]’ objects the current object is connected to, so we use the do command to loop through all of them. After the do command you will see the following token:
~From>()~To.State [Watch]
Though this may look a bit cryptic at the first glance, it just says to find all ‘From’ roles for the current object first, then follow them through the relationship in that binding to the respective ‘To’ roles and thence to the ‘State [Watch]’ objects connected to these roles. The ‘~’ prefixes denote the roles and the ‘>’ prefix refers to the relationship. The only extra trick here is that – unlike previously where we used exact type names to access design elements – we now use the special() token after ‘>’ to access any kind of relationship that is bound to the ‘From’ roles.

Within the body of this inner loop we thus iterate over all State objects that are reachable in one From-To ‘hop’ from the outer loop’s State. The content of the inner loop is pretty clear: output some spaces, then the name of the accessed object and a line break. Note how the context has changed within the loop: the current element is now the target State object, whereas in the outer loop it is the source State object. The output of :State Name; in line 10 is thus different from the output of :State Name; in line 4. As we descend through loops, we thus build up a stack: each element on the stack corresponds to the current element in each loop level. Most often, the information you want to output will be from the current loop level. If you want information from another model element, it will often be available in an outer loop level. For instance, if we wanted to output each source and target state as a pair on a line, we could remove all output from the outer loop, and have a line in the inner loop that accessed the element from the outer loop with the ;1 suffix:
:State name;1; ' -> ' :State name;
Using information like this from outer loops often replaces what would be done with variables in a generic programming language. This syntax is shorter, removes the need to define variable names, remember them, and make sure their values are not overwritten before they are used. For the relatively rare cases where variables are still needed, MERL offers powerful associative variables along with a simple shortcut syntax for common cases: see Section 5.3.6.

After the inner do loop the generator definition is reasonably trivial, just setting a line break before the main loop is iterated again. Note that we are not back in the outer loop, so :State name; here would refer again to the same element as in line 4.

As a general rule, generator keywords should always be preceded by white space (space, tab, or carriage return) and they can be optionally followed by a semicolon, ‘;’. Type names that contain spaces should be followed by a semicolon. This is not needed in the chaining of type names, where the next type prefix ‘.>~#:’ is sufficient to terminate the previous type name, e.g. ‘.State [Watch]~To’.

Up Previous Next Title Page Index Contents