Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 10 Next »

Template regions

ST introduces a finer-grained alternative to template inheritance, dubbed regions. (Regions are similar to a feature in Django). This feature allows a programmer to mark a location or series of lines in a template, and give it a name. A subgroup which inherits this template can provide replacement code to override just the named region. This avoids having to override the supergroup's template with a whole replacement template, when just a small addition or replacement is needed. While regions are syntactic sugar on top of template inheritance, the improvement in simplicity and clarity over normal coarser-grained inheritance is substantial.

Add text at a location

For example, in a code-generation scenario, imagine using the following template called method to produce the text for a method:

group Java;
method(name,code) ::= <<
public void <name>() {
    <code>
}
>>

Suppose that you want also want the method template to be able to optionally generate method code that includes debugging statements. (To be clear about this example: this would be debugging code to debug the generated Java method, not code to debug the template itself.)

You could employ conditionally included subtemplates (using <if(...)> etc)  around the debugging lines, but that clutters up the templates of the Java group considerably, and also fails to achieve proper separation of concerns.

Instead you would like to have all debugging stuff encapsulated in a separate template group which focuses on debugging. In that template group, you could create an overriding method template by copying and pasting the entire method template and inserting your additions. But then you are duplicating all of that output literal text, which breaks the "single point of change principle."

Instead just leave a hole that a subgroup can override, here a location marked with <@preamble()>:

group Java;
method(name,code) ::= <<
public void <name>() {
    <@preamble()>
    <code>
}
>>

In a template subgroup focusing on debugging (group dbg), define the region using a fully qualified name which includes the region's surrounding template name, @method.preamble(), and supply the replacement text:

group dbg : Java;
@method.preamble() ::= <<System.out.println("enter");>>

Regions are like subtemplates scoped within a template, hence, the fully-qualified name of a region is @t.r() where t is the enclosing template and r is the region name.

Replace a region of existing template text

Consider another problem where you would like, in a template subgroup, to replace a small portion of a large inherited template. Imagine you have a template that generates conditional statements in the output language, but you would also like to be able to generate a debug version of these statements which track the fact that an expression was evaluated.

(To be clear about this example, here the template's purpose is to produce "if" statements in the output language, here Java. That "if" is unrelated to the issue of using template <if(...)> expressions, which we are discussing how to avoid.)

Again, to avoid mingling debug version code with your main templates, you want to avoid "if dbg" type template expressions. Instead, mark the region within the template that might be replaced by an inheriting subgroup focusing on debugging. Here the code is marked with the pair of markers <@eval>...<@end>:

group Java;
test(expr,code) ::= "if (<@eval><expr><@end>) {<code>}"

where <@r>..<@end> marks the region called r. Now a template subgroup can override (replace) this region:

group dbg : Java;
@test.eval() ::= "trackAndEval(<expr>)"

Regions may not have parameters, but because of the dynamic scoping of attributes, the overridden region may access all of the attributes of the surrounding template.

In an overridden region, @super.r()refers to the supergroup template's original region contents.

(I'm guessing this is trying to say: Within the replacement template text, ie: right-hand-side, you can use the symbol @super.r() to insert the original region contents.  Also guessing that "super" is a keyword, and should not be replaced, while "r" should be replaced with the actual region name. Pretty sure this needs to be enclosed in expression delimiters, not just bare. -- GW)

  • No labels