Search code examples
rascal

How to control layout in different parts of syntax?


I am looking at the Exp example in the Tutorial.

Is it possible to control layout conditionally? Consider, for example, Python expressions:

  • Newlines are irrelevant while inside a parenthesized expression
  • Otherwise, a newline is a statement/expression terminator

For example: (1 + \n 3)

is a valid expression, but 1 +\n 3

is not.

If not, what would be the easiest way of achieving the same result, short of sprinkling newlines through my grammar?


Solution

  • Yes it's possible:

    • if you use a layout non-terminal L in a syntax rule between two normal symbols A and B like so: syntax NY = "foo" A L B "bar", then Rascal will not add more layout non-terminals between the A and L or between L and B
    • you can add layout non-terminals to your grammar which are not automatically inserted all the time (for use in the first point) like so: layout NoNewLineLayout = @manual [\t\ ]*;

    So this requires sprinkling instances of NoNewLineLayout symbols in your grammar, rather than sprinkling newlines. I normally use a short name like NNL to make this less intrusive. We used this workaround for experimenting with Javascript grammars and other layout sensitive languages. In general, though it is not perfect and we've been working more elegant solutions, see http://dl.acm.org/citation.cfm?id=2814242 for a preview.

    A second less flexible solution is to use the scope of layout definitions (which is module scoped). The layout definition in the current module takes precedence over any imported layout definitions. In such a way one can influence which layout non-terminal is woven in which rules. This comes mostly in handy when embedding languages into other languages which may have different comment conventions and such; for the current use case, I wouldn't advise it.