Skip to content

Instantly share code, notes, and snippets.

@nulldatamap
Created July 23, 2014 00:46
Show Gist options
  • Select an option

  • Save nulldatamap/a41f39f49678fc7faef4 to your computer and use it in GitHub Desktop.

Select an option

Save nulldatamap/a41f39f49678fc7faef4 to your computer and use it in GitHub Desktop.
templator_format.md
# The Templator format
The Templator foramt is a format for generating source code files from a set of structured data.
It's relatively flexible making it applicable for a large amount of different input data.
## Contents:
* #### API
* #### Syntax
* #### Semantics
* #### Examples
## API
`render_template_file( f, values, outfile=None )`
Takes a path to a template source file (`f`), the input data that should be applied to the template
(`values`) and if specified will write the rendered template to `outfile`, otherwise to the original
template file itself.
Returns `0` on success and `1` on error. If an error occurs it will be printed to `stdout`.
`render_template( src, values, keep_original=True )`
Renders the given template source `src` with the given `values`. If `keep_original` is true the template part of the template file will be returned concatenated with the rendered template.
Returns `0` on success and `1` on error. If an error occurs it will be printed to `stdout`.
## Syntax
The Templator file consists of two segments, the _definition_ segment, and the _body_ segment. Both are enclosed with two lines only containing `/*` amd `*/` respectively.
The syntax is defined in [EBNF](http://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form) as:
```ANTLR
SPACING := TAB | " "
WHITESPACE := ( NEWLINE | SPACING )+ ;
NAME := -( WHITESPACE | ESCAPE | "${" | "%{" | "?{" | "}" | "." ) + ;
COMMENT := "#", (-NEWLINE)+, NEWLINE ;
ESCAPE = "$$" | "$/" |"$." | "$n" | "$%" ;
SUBTEMP_TAG := "%{", SPACEING*, NAME, ( "with" | "for", SPACING+, NAME )?, SPACING*, "}" ;
BODY_SEGMENT := ( SUBTEMP_TAG | ESCAPE | -"*/" )* ;
IF_TAG := "?{", SPACEING*, "if", SPACING+, "not"?, SPACING+, "first"|"last", ":", ( ESCAPE | (-NEWLINE) + ) ;
VAR_TAG := "${", SPACING*, NAME, SPACING*, "}" ;
TAG := VAR_TAG | IF_TAG | SUBTEMP_TAG ;
SUBTEMPLATE := NAME, NEWLINE, ( TAG | ESCAPE | -NEWLINE, NEWLINE )+, "." ;
DEFINITION_SEGMENT := ( WHITESPACE | SUBTEMPLATE | COMMENT )*, "@BODY" ;
TEMPLATE := "/*", NEWLINE, DEFINITION_SEGMENT, BODY_SEGMENT, "*/", ANYTHING ;
```
**Note that `ANYTHING` is not greedy, else this the syntax would be broken.*
## Semantics
In the defition segment subtemplates are defined. Subtemplates consists of thier name, then their body and a `.` to terminate them. The body is raw text as-is except for the tags inside.
Tags come in 3 flavours:
* Variable tag: `${ variable_name }` or `${}`, which replaces itself with the giving variable if present in the current value. If the variable is empty ( `${}` ) then the current topvalue is inserted instead of a subvalue of it.
* If tag: `?{ if not last:raw text here}` or `?{ if first:also raw text}`, which if the condition is met, replaces itself with the text directly following the `:` and trailing the `}`. Current a condition can be either `if first` or `if last`, these can also be negated with `if not last` and `if not first`. Note that any condition with uses `first` or `last` is always false if it's note a part of an iterable.
* Subtemplate tag: `%{ foo }`, `%{ foo with var_bar }` or `%{ foo for var_bar }`, which replaces itself with the result of the specified subtemplate being rendered. Passing the values that the subtemplate will be rendered can be done in 3 different ways:
- `%{ subtemp }`, which just passes the current value along (on top-level that is always the data structure passed to the `render_template` function) to the given subtemplate.
- `%{ subtemp with val }`, which passes `val` (which belongs the current value) on to the specified subtemplate.
- `%{ subtemp for vals }`, which iterates over `list`s and `tuple`s calling the specified subtemplate with each element. If the specified iterable value is a `dict`, the subtemplate will be called with a key value structure: `{ "key": ..., "value": ... }`. If the specified value isn't iterable the program will fail with an error.
After the definition of subtemplates comes the body of the template. The body may contain subtemplate tags which are then resolved. This is done multiple time until the rendered body can't be resolved any further. This enables all kinds of weird recursion, though the recursion limit is a `100`.
### Escape codes
In order to avoid plain-text source code to clash with the syntax of Templator a set of escape codes are available:
`$$` → `$`
`$/` → `*/`
`$.` → `.`
`$n` → `\n`(newline)
`$%` → `%`
## Examples
These examples are here to demonstrate the semantics of Templator.
#### #1:
```
/*
# This takes the top-value given, and resovle to the value displayed with
# indentation and a trailing comma and newline, but only if it's not the
# last element in the list.
list_stuff
${}?{ if not last:,$n}
.
@BODY
My list of stuff:
%{list_stuff}
*/
```
Given `[ 1, 2, 3, 4 ]` as it's data, it would resolve to:
```
My list of stuff:
1,
2,
3,
4
```
#### #2:
```
/*
# Here, we are going to list some more complex data.
list_developer
${name}:
Job: ${job}
Previous projects: %{list_projects for projects}
?{ if not last:$n}
.
# Here we basically do the same as in #1
list_projects
${}?{ if not last:, }
.
header
${studio}'s is working on their game ${game}.
The devlopment team is:
%{list_developer for developers}
.
@BODY
%{header}
They are hiring QAs though.
*/
```
Given the following data:
```
{ "studio": "Lioncloth Intertainment"
, "game": "Mogworld"
, "developers": [ { "name": "Simon Northbridge"
, "job": "Programmer"
, "projects": [ "Interstellar Bum Pirates" ] }
, { "name": "Sasha Caldwell"
, "job": "Lead artist"
, "projects": [ "Skywards", "Call of Duty 39" ] }
, { "name": "Don Sonderland"
, "job": "Lead programmer"
, "projects": [ "Interstellar Bum Pirates"
, "Project 11"
, "Bullet Madness 3"
, "Magizalius" ] } ] }
```
Resolves to:
```
Lioncloth Intertainment's is working on their game Mogworld.
The devlopment team is:
Simon Northbridge:
Job: Programmer
Previous projects: Interstellar Bum Pirates
Sasha Caldwell:
Job: Lead artist
Previous projects: Skywards, Call of Duty 39
Don Sonderland:
Job: Lead programmer
Previous projects: Interstellar Bum Pirates, Project 11, Bullet Madness 3, Magizalius
They are hiring QAs though.
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment