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

Opening a Generator Editor
Creating a new generator
Executing generators
Debugging generators
Editing generator definitions
Building generators from the desired output
Font formatting in generators
Changing the editing area font and word wrap
Deleting generators
Renaming generators
Saving generator definitions
Writing generator definitions to files
Reading generators from files
Finding and replacing text within generator definitions
Checking syntax
Adding and removing breakpoints in generator definitions
Enabling and disabling breakpoints
Setting breakpoint condition
Tracing call context
Comparing generator versions
Generator icon

5.3.1 Using the Generator Editor

In the following we shall describe the features and functions of the Generator Editor.

Opening a Generator Editor

As there are several places in MetaEdit+ where generators are used or referred to, there are also multiple ways to open the Generator Editor. The simplest way is to open it from the main MetaEdit+ window:
1)Select a graph or graph type in the current browser.
2)Select Metamodel | Generator Editor, select Edit Generators from the popup menu or press the Generator Editor toolbar button.

The Generator Editor is opened for editing the generators in the selected graph type. For example in Figure 5–10 the Generator Editor is open for graphs of type ‘WatchApplication’. To work with generators for other modeling languages select Generator | Change Graph Type... in the Generator Editor.

The Generator Editor can also be opened from an editor such as a Diagram Editor by selecting Graph | Edit Generators..., or from Tools | Generator Editor in a Graph Tool. To open a new Generator Editor from the Generator Editor itself, select Generator | Open in New Window.

Generators are also used to define identifiers, text symbol elements, symbol element conditions and subobjects and subsymbol names for templates. The Generator Editor for these purposes can be opened from the respective editing tool (an Object Tool or other metamodeling tool, or a Symbol Editor’s Format dialog).

Creating a new generator

Generators are always defined specific to a given graph type, because the generator uses the data structures of the graph type in its definition. The following generator is appropriate only for WatchApplications, thus for testing it you should have a Generator Editor opened for WatchApplication.

To make a new generator select Generator | New... from the menu or toolbar. You will be asked for the name of the new generator. Certain names and prefixes have been reserved for special purposes (see Section 6.2.1), but otherwise any name will do.

To proceed with creating our example generator enter a name like ‘Test’ and press OK. The contents of the editing area are now:
Report 'Test'

endreport
The meaning of these lines is described in the following subsections, but now we can continue the definition. The next step is to select the operation and object type that we will be operating on. To proceed with generator definition, put the cursor on the blank (second) line:
1)Select the ‘Control’ (or ‘Templates’) category in the Concept Box (with the left mouse button).
2)Double click ‘foreach’ from the Choice box.
Or
2)Select ‘foreach’ from the Choice Box with the left mouse button and select Insert from the Choice Box pop-up menu.

The contents of the editing area are now:
Report 'Test'
foreach type 
{
}
Endreport
If the inserted template has an argument, e.g. a condition or type filter, that part will be selected for you in the generator definition to ease the insertion of proper content. For instance, here the keyword ‘type’ will be selected, as you will need to replace that with an actual type.
->For the following templates: /* */, if, foreach, do, dowhile, filename and variable you can also make some existing text in the generator definition become the body of an inserted template. Select the text and hold down the shift key while inserting a command template. For example, to insert an ‘if’ command around an existing part of the generator definition, select that part, hold shift down and double-click the ‘if’ template. The ‘if’ template will be inserted around the existing part, which becomes the ‘then’ block, and the condition part of the ‘if’ template will be selected.

After operation selection we proceed by selecting an object type. Because we are interested in State objects:
1)Select the text type in the Editing Area if it is not already selected.
2)Click ‘Object’ in the Concept Box.
3)Double-click ‘State [Watch]’ in the Choice Box. Alternatively you can select ‘State [Watch] and choose Insert from its pop-up menu.

As a result of the selection the text .State [Watch] is added into the Editing Area, replacing the selected type text. Notice that the concept was automatically preceded with its type character, the dot (others being : for Property, > for Relationship, ~ for Role and # for Port).

The next step is to add the desired operations for the objects in the loop. The operations to be performed for each object of the specified type (in this case State) are placed within the curly brackets. To print out the name of each State:
1)Place the mouse cursor after the opening bracket.
2)Select ‘Object’ from the Concept Box.
3)Open the sub-branch for State [Watch] in the Choice Box.
4)Double-click State name from below State [Watch] in the Choice Box tree view.

After this operation the generator specification looks like this:
Report 'Test'
foreach .State [Watch]
{  :State name;
}
endreport
Notice that most statements in a generator definition can be optionally terminated by a semicolon, ‘;’, but the semicolon must be used after type names which contain spaces: otherwise the parser could not tell whether “:Customer type” was a command to output the “Customer type” property, or a command to output the “Customer” property and a second command to output the type of the current element.

Executing generators

Now, if we think that this generator might work, we can test it by running it by selecting Generator | Generate from the menu bar or toolbar. This operation executes the generator specification against a graph of the current type: if no graph has yet been picked, you will be asked to specify which graph in a dialog. If you want to change to try the generator against a different graph, select Generator | Generate for Graph.... We can run and adjust the generator until we are satisfied.

We notice however, that we need to add some strings into the output and that we should separate the output for each State onto a new line. To make these modifications we extend the generator definition as below:
Report 'Test'
foreach .State [Watch]
{  'State : '
   :State name;
   newline
}
endreport
By executing the generator again, we can see what the result looks like (Figure 5–11). See Section 5.2.1. in the ‘MetaEdit+ User’s Guide’ for more information about the Generator Output Tool.

Generator Output for Time 1

Figure 5–11. An example of a generator output.

Debugging generators

The debugging of generators is explained in Section 5.4.

Editing generator definitions

To view and edit existing generator definitions select any of the generators from the Generator Box. After the operation the generator definition will be shown in the Editing Area. If your current generator has been modified and not saved, you will be prompted whether to save it first.
->A new generator only appears in the Generator Box when it has been saved.

You can continue making the ‘Test’ generator. For example, the next major improvement for the ‘Test’ generator could be adding for each State a list of other States it is connected to. After this modification the new generator definition should look like:
Report 'Test'
foreach .State [Watch]
{  'State : '
   :State name;
   newline
   'Connects to: '
   newline
   do ~From>()~To.State [Watch]
   {  ' 	'
      :State name;
      newline
   }
   newline
}
endreport
The behavior of this generator is explained in more detailed in Section 5. For now, we will concentrate on the use of the Generator Editor. When we execute the modified generator, the result looks like Figure 5–12 below.

Generator Output for Time 2

Figure 5–12. Generator output for ‘Test’ generator.

Building generators from the desired output

One approach to building a generator is to start with the desired output as one large fixed string in the generator, and progressively refactor it and replace fixed parts with values from the model. You can paste the desired output as a fixed string with Edit | Paste Quoted, which will paste the current clipboard contents surrounded by single quotes, with any single quotes in the contents escaped by doubling them. E.g. if your desired output is:
Generated from graph Foo by MetaEdit+'s MERL
You can copy and paste that with Paste Quoted, resulting in the following (note the doubled apostrophe):
'Generated from graph Foo by MetaEdit+''s MERL'
You can then replace a varying part of the result with a property from the model by selecting that part of the string and shift-double clicking the desired property in the Choice Box. This will automatically close the string quotes, insert the property output command, and re-open the string quotes. E.g. if you select Foo and shift-double click Name, the result is:
'Generated from graph ' :Name ' by MetaEdit+''s MERL'

Font formatting in generators

Basic character formatting like underline, italic, bold or font color and background color can be applied to commands in the generator definition. It is also possible to attach a hyperlink to the selected text. Font formatting options are applied to the selection from the Format menu or toolbar buttons, or by pressing one of the shortcut keys (Help | Shortcut keys, see also Section 3.3.4 in ‘MetaEdit+ user’s Guide’). To remove all formatting and colors from the selection, choose Format | Remove Character Formatting from the menu.

The formatting of the generated output is taken from the first character of the clause that generated the output. This is then applied on top of any formatting present in the output from that command. For example, given an object whose id is Account, the command id with italic emphasis would be output as Account. If the property value were a Text in bold, the output from id would be Account, and from an italic id the output would be Account.

Note that for literal string clauses, the formatting is read not from the opening ' but from the first character of the actual string. For property and chain output commands, the formatting is taken from the type prefix :.>~# of the first element, e.g. the . and > respectively in .ObjType:PropName and >RelType~RoleType:PropName.

Note that the syntax coloring of MERL (dark red for string output commands like 'some text' and dark green for explicit type names like .Object or property local names like :Name) is set automatically when the generator is parsed. The syntax coloring is also shown in the output, to make it easier to see what is a model value and what is fixed text. Syntax coloring is not however shown in output to a Text element in a symbol, in identifier generators, or in the Live Check pane.

Output from a model element will be turned into Live Code links, shown with a light blue underline. Double-clicking a Live Code link in the output will take you to the original model element. This can be useful to the user of the generator output, as well as for debugging and tracing while writing the generator. Note that while generating, the Live Code link for a command is applied after any translator suffixes, so e.g. id%var will have a link, even though translators cannot preserve formatting. Live Code links are only active within MetaEdit+. They are not shown in output to a Text element in a symbol, or in identifier generators.

Some operations do not preserve formatting, e.g. saving either generators or output to a text file, exporting generators in XML files, or using translators on generator output. An empty translator can thus be used to remove formatting where it is not wanted, e.g. to translate :Name; endto.

Changing the editing area font and word wrap

You can change the font and word wrap settings of the generator editing area from the View menu. Note that these changes only affect this editor, and not the saved generator or resulting output.

Deleting generators

To delete the currently selected generator choose Generator | Delete... from the menu (or from the toolbar or with the keyboard shortcut Ctrl+D). A dialog prompts for the confirmation of the deletion operation. If no generator is selected, the dialog will allow the selection of multiple generators to delete.

Renaming generators

A generator can be renamed by selecting Generator | Rename... or by pressing F2. This brings up a dialog for entering a new name. As generators are called dynamically based on the current graph type and a possibly dynamic name, calls to the generator cannot be automatically updated to reflect the new name. You can use Edit | Advanced Find to find occurrences of XXX() or subreport 'XXX' run, e.g. with the following regular expression, replacing XXX with the old name of your generator:
XXX\(|subreport;?\s+'XXX';?\s+run
You can also rename the generator by changing its name at the beginning of the generator definition. When the definition is saved, you will be asked whether you want to create a new generator with the new name, or rename the existing generator to the new name.

Saving generator definitions

Generator definitions can be saved with the menu selection Generator | Save (or from the toolbar or with the keyboard shortcut Ctrl+S). If the current definition has been modified but not saved and the Generator Editor is closed or another definition is chosen from the Generator Box the tool will ask whether the generator definition should be saved.

Writing generator definitions to files

Generator | Write to file... (or the corresponding toolbar command) lets you write the current contents of the editing area to a text file. Note that only the text is saved, not any formatting applied with shortcut keys. It is also possible to save all currently listed generator definitions by selecting Write to file... while having no selection in the list. Where possible, the file timestamp is set to match the generator modification timestamp.

Reading generators from files

Generator | Read from file... (or the corresponding toolbar command) lets you read an existing generator definition from a text file. When reading from a file, you are normally warned if the generator would have the same name as an existing one. Also, the generator is not actually saved, but is left in the text area, ready to be saved explicitly or via a prompt when you select another generator definition or close the Generator Editor. You can also select multiple generator definitions to be read at the same time. In this case, each generator is saved automatically without further interaction with the user. The generator timestamps are set to match the file timestamps.

Finding and replacing text within generator definitions

Edit | Find... (or Ctrl+F or the corresponding toolbar command) lets you find text in the current generator definition. You can press the F3 key to find the next occurrence in the generator, or Shift+F3 to find the previous occurrence. If you want to replace text, use Edit | Replace... which allows replacing text in forward and backward direction in the current generator definition.

Edit | Advanced Find... (or Ctrl+Shift+F or Shift+Find on the toolbar) lets you find text in many generator definitions and use regular expression searches. The current generator must be saved before using this. In the Advanced Find dialog you can click the button to the right of the Find Text box to see the list of the available regular expression patterns. When you select a regular expression pattern from the list, the expression is entered to the current find text and the ‘Regular Expression’ checkbox is checked. The search results are shown in the Generator Box titled: ‘Last Find:’ followed by the search string used. The results can be browsed by using the F3 and Shift+F3 which shows the next/previous occurrence of the Find Text in the selected generator, or if none is found, the next/previous occurrence in the next generator will be shown.

The scope constrains the number of generators that are matched against the search criteria:
*All Graph Types: find generators in all open projects
*This Project: find generators in graphs that belong the the same graph type as the selected generator.
*This Graph Type: find generators in the currently selected generator's graph type, or if nothing is selected, find in the Generator Editor’s current graph type.
*This Graph Type and Supertypes: same as ‘This Graph Type’ but also finds generators in the supertypes of the current Graph type.
*Current Generator: find in the currently selected generator's last saved text.
Note that when the Regular Expression checkbox is checked, ( ) * + . ? [ and \ are special characters and must be preceded with backslash if they are intended literally. Information about the regular expression syntax is available in Appendix A: Regular expressions, with more general information and guides on the Internet (e.g. http://en.wikipedia.org/wiki/Regular_expression).

Checking syntax

The syntax of a generator definition is automatically checked and possible errors reported when the definition is saved. To check the syntax while writing the definition, select Edit | Check Syntax.

Adding and removing breakpoints in generator definitions

Breakpoints provide a means for interrupting the execution of a generator in user-definable position for debugging purposes. To add a breakpoint in a generator definition:
1)Move the cursor to the desired breakpoint position in the editing area.
2)Select Breakpoint | Add from the menu or from the toolbar. A red circle appears in the selected location to denote the new breakpoint.

To remove breakpoints:
1)Select the breakpoints that you want to remove in the editing area.
2)Select Breakpoint | Remove from the menu or from the toolbar.

To remove all breakpoints from the definition, select Breakpoint | Remove All from the menu. To remove all breakpoints from all generators in all loaded Graph types, select Breakpoint | Remove All Globally from the menu.

Enabling and disabling breakpoints

To customize the behavior of all breakpoints, select one of the following options from the Breakpoint menu:
*Enabled: Breakpoints are enabled in most cases when generator is executed (i.e. from Generator Editor, Editor, Graph or Type Browser, etc.) but not when executed as part of a symbol element’s display condition, in a symbol element text field, or in an identifier generator.
*Enabled While Editing: Breakpoints are active only when the generator is executed from the Generator Editor.
*Enabled While Debugging: Breakpoints are active only when the generator is executed from the Generator Editor by using the Debug... command.
*Disabled: Breakpoints are always ignored.

Setting breakpoint condition

A breakpoint can also have a condition that defines whether or not the breakpoint will be activated when it is encountered. Conditions are defined as generator snippets that are evaluated in the current context and the output compared to the supplied string or regular expression. To set the condition, select the breakpoint and then Breakpoint | Edit Condition to open the Format Breakpoint dialog (shown in Figure 5–13). If no breakpoint is selected, a new one with an empty condition is first added at the start of the selection.

Breakpoint Condition

Figure 5–13. Setting breakpoint condition.

The condition term is defined in the Condition source compartment of the dialog. Select None for the normal breakpoint behavior (i.e. always interrupt the execution at the breakpoint) or define the Generator that provides the condition term. The Condition part of the dialog then defines how to compare the term in order to meet the interrupt condition. Select String and an appropriate comparison operation for plain string comparison or RegExp and either = or <> for regular expression comparison.

Tracing call context

To see where a generator is called by its parent in the hierarchy, select the generator and choose Generator | Show Call Context. This will select the parent generator in the hierarchy and highlight the subgenerator call.

Comparing generator versions

To track the current changes made to the generator definition after the last saving, select Generator | Compare with Saved. This will open a Changes window that shows the saved versions and current version with changes highlighted.

Generator icon

A generator can have an icon that will be shown if the generator is included in the Diagram Editor’s toolbar (i.e. it has a ‘!’ prefix in its name). To open the Icon Editor for the generator select Generator | Icon Editor.

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