Show in Frame No Frame
Up Previous Next Title Page Index Contents Search

5.2.5 Navigation revisited

In the initial version of our example generator we used foreach and do loops, without any filtering or explicit ordering, to go through the elements on the Graph level, to access property values and subgraph links, and to navigate along roles and relationships. While this approach seems to work fairly well in our limited example, it is not perfect by any means. For example, the outermost foreach loop handles the WatchModel relationships in the default alphabetical order, which may not be the order we want them to appear in our spec sheet. If we want them to appear in the same order as they appear vertically in our diagram, we can augment the foreach command with an orderby clause:
foreach >Watch; orderby y num
The above can be read simply as ‘go through all the Watch relationships in ascending order according to their y coordinates, sorted as numbers’. The num is important: otherwise they will be sorted as strings, which places ‘100’ before ‘99’. Note also the semicolon to show MERL where the relationship type name finishes; otherwise the rest of the line would be considered part of the type name. (A line break or open brace ‘{‘ would also suffice to end the type name, since ‘{‘ cannot be in a literal type name in MERL unless escaped as ‘\{’.)

Another problem arises when we are outputting the button names. We used a blank character to separate the names, but what would happen if we were using the more usual comma character as a separator? The MERL code would look like this:
do :Buttons { id ', ' }
The example output would now be:
Buttons: Mode, Set, Up, Down,
This isn’t ideal, as we don’t want an extra comma after the list of the names. The simple solution is to replace do with dowhile: when iterating over the last element of the loop, dowhile skips all simple string commands at the end of the loop:
dowhile :Buttons { id ', ' }
The output will now look like this:
Buttons: Mode, Set, Up, Down
There is also another ordering problem looming when we fetch the names for applications within the LogicalWatch’s subgraph. The loop command we are using for this retrieves the State [Watch] objects in the default alphabetical order. Adding an orderby clause doesn’t help here, as the order we want isn’t easily expressible as a sortable value for each element. The best order is probably that of the Transition relationships, which define the cycle of applications within the LogicalWatch. The cycle starts from the start state and flows from each State [Watch] object to the next through the directional Transition relationships. This requires somewhat more complex navigation in the subgraph. As there is only one Start in each WatchApplication graph (as defined by an occurrence constraint), we can use a simple foreach command to get to the starting point for our navigation. The MERL code for this and the consequent navigation to the first State [Watch] object looks like this:
foreach .Start [Watch]
{ do ~From~To.() { /* some code here */ } }
We find the Start, then navigate along the From role and To role into the object at the other end. (Here we use the wildcard .(), meaning any object; we could also explicitly write .State [Watch].) The navigation from one State [Watch] to the next is similar:
do ~From~To.()
There is now, however, a catch: as there is no explicit Stop state in our graph and the number of State [Watch] objects differs between different graphs, how do we know when to stop looping? The solution is to keep track of the objects as we pass through them, and stop when we encounter an object we have already visited. The next section discusses how this can be done with recursion and subgenerators.

Show in Frame No Frame
Up Previous Next Title Page Index Contents Search