About

The "template language" is a language that aims to eliminate redundancy in the specification of grammar, completion templates, and pretty printer. It borrows syntax from SDF and StringTemplate.

Syntax Overview

Productions
Sort = < e* > Template with elements e*
Sort.Constructor = < e* > Template with elements e*
Sort = [ e* ] Template with elements e* (alt. brackets)
Sort.Constructor = [ e* ] Template with elements e* (alt. brackets)
Placeholders
<Sort> Placeholder (1)
<Sort?> Optional placeholder (0..1)
<Sort*> Repetition (0..n)
<Sort+> Repetition (1..n)
<Sort*; separator="\n"> Repetition with separator
<Sort; text="hi"> Placeholder with replacement text
<Sort; hide> Placeholder hidden from completion template
Priority specification
context-free priorities
  {left: Exp.Times Exp.Over} >
  {left: Exp.Plus Exp.Minus}
Refer to productions using sort and constructor name
Lexical syntax
lexical syntax
  ID = [A-Za-z] [A-Za-z0-9]*
Lexical syntax similar to SDF

Pretty printing

Overview

The pretty printer that is generated from syntax templates consists of a number of Stratego strategies. Each matches a particular pattern in the AST. If the pattern matches, the strategy (recursively) invokes the pretty printing strategies for the child nodes, and combines the results into a BOX AST. This BOX AST can then be converted to a string using the box2text-string strategy from libstratego-gpp.

For example, for a simple plus-expression syntax template:

  Exp.Plus = <<Exp> + <Exp>> {left}

the pretty printing strategy that may be generated is:

  prettyprint-Exp:
    Plus(a, b) ->
      [ H([SOpt(HS(), "0")], [ <pp-one-Z(prettyprint-Exp)> a, S(" + "), <pp-one-Z(prettyprint-Exp)> b ]) ]

As you can see, the pretty printing strategies return a list of boxes that the caller should wrap in a V or Z box (among other things, that is what pp-one-Z does). The user is responsible for this when invoking one of the prettyprint-* strategies from their code!

All pretty printing strategies that are specific to a symbol are hooked up to one global prettyprint-LanguageName strategy, so that it is easy to pretty print an arbitrary subtree of an AST without knowing the type of the root node in advance:

  prettyprint-LanguageName = prettyprint-Exp

Parenthezation

In Spoofax, it is common to not parse parentheses to an AST node. After all, the fact that parentheses are necessary at some point in an expression can be inferred from the priorities of the operators (which are specified in the grammar) and the structure of the AST. The tool sdf2parenthesize does exactly this, and is integrated into SpoofaxLang? via the parenthesize-LanguageName strategy. Invoking the parenthesize-LanguageName strategy results in the addition of Parenthetical constructors to the AST at every place where the structure of the AST conflicts with the operator priorities specified in the grammar. The generated pretty printer knows how to handle the Parenthetical constructor, because a syntax template for parentheses with the bracket attribute, such as:

  Exp = <(<Exp>)> {bracket}

generates the pretty printing strategy:

  prettyprint-Exp:
    Parenthetical(a) ->
      [ H([SOpt(HS(), "0")], [ S("("), <pp-one-Z(prettyprint-Exp)> a, S(")") ]) ]

How to use

The idiomatic way to invoke the generated pretty printer, including parenthezation, and a conversion to string (with word wrap at the 100th column, if applicable), is:

  prettyprint-LanguageName-string =
    parenthesize-LanguageName
    ; prettyprint-LanguageName
    ; !V([], <id>)
    ; box2text-string(|100)

-- TobiVollebregt - 01 Feb 2012

Revision: r1.3 - 13 Mar 2012 - 15:53 - TobiVollebregt
Spoofax > TemplateLanguage
Copyright © 1999-2020 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback