# Twig Template Engine Specification

This specification specifies a simple cross-language template engine for at least PHP, Python and Ruby.

# Purpose

A language independent and simple template engine is useful for applications that use code which is written in more than one programming language. Good Examples are portal systems which use a blog written in Ruby, a forum software written in PHP and a planet system written in Python.

# Inspiration

Twig uses a syntax similar to the Genshi text templates which in turn were inspired by django which also inspired Jinja (all three of them python template engines) which inspired the Twig runtime environment.

# Undefined Behavior

To simplify porting the template language to different platforms in a couple of situations the behavior is undefined. Template authors may never take advantage of such a situation!

# Syntax

I'm too lazy to write down the syntax as BNF diagram but the following snippet should explain the syntax elements:

    <!DOCTYPE HTML>
    {# This is a comment #}
    <title>{% block title %}Page Title Goes Here{% endblock %}</title>
    {% if show_navigation %}
    <nav>
      <ul>
      {% for item in navigation %}
        <li><a href="${item.href|e}">$item.caption</a></li>
      {% endfor %}
      </ul>
    </nav>
    {% endif %}
    <article>{% block body %}{% endblock %}</article>

## Comments and Whitespace

Everything between `{#` and `#}` is ignored by the lexer. Inside blocks and variable sections the Lexer has to remove whitespace too.

## Output Expressions

To output expressions two syntaxes exist. Simple variable output or full expression output:

    $this.is.a.variable.output
    ${ expression | goes | here }

The former is what we call a variable expression, the second a full expression. Variable expressions must not contain whitespace, whereas a full expression must print the output of the full wrapped expression.

## Expressions

Expressions allow basic string manipulation and arithmetic calculations. It is an infix syntax with the following operators in this precedence:

> Operator | Description
> --- | ---
> `+` | Convert both arguments into a number and add them up.
> `-` | Convert both arguments into a number and substract them.
> `*` | Convert both arguments into a number and multiply them.
> `/` | Convert both arguments into a number and divide them.
> `%` | Convert both arguments into a number and calculate the rest of the integer division.
> `~` | Convert both arguments into a string and concatenate them.
> `or` | True if the left or the right expression is true.
> `and` | True if the left and the right expression is true.
> `not` | negate the expression

All number conversions have an undefined precision but the implementations should try to select the best possible type. For example, if the implementation sees an integer and a float that looks like an integer it may convert the latter into a long and add them.

Use parentheses to group expressions.

If an object cannot be compared the implementation might raise an error or fail silently. Template authors may never apply mathematical operators to untrusted data. This is especially true for the php implementation where the following outputs `42`:

    ${ "foo41" + 1 }

This is undefined behavior and will break on different implementations or return `0` as `"foo41"` is not a valid number.

### Types

The following types exist:

> Type | Literal | Description
> --- | --- | ---
> `integer` | d+ | One of the two numeric types. Which of them is used and when is up to the implementation.
> `float` | d+.d+ | Floating point values.
> `string` | see below | A unicode string. The PHP implementation has to use bytestrings here and may use mb_string.
> `bool` | (true|false) | Represents boolean values.
> `none` | none | This type is returned on missing variables or attributes.

String regex:

    (?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')(?sm)

### Attribute Lookup

There are two ways to look up attributes on objects. The dot and the subscript syntax, both inspired by JavaScript. Basically the following expressions do the very same:

    foo.name.0
    foo['name'][0]

This is useful to dynamically get attributes from objects:

    foo[bar]

The underlaying implementation is free to specify on it's own what an attribute lookup means. The PHP reference implementation for example performs those actions on `foo.bar`:

- try `$foo['bar']`
- try `$foo->bar()`
- try `$foo->bar`
- try `$foo->getBar()`

The first match returns the object, attribute access to nonexisting attributes returns none.

### Filtering

The template language does not specify function calls, but filters can be used to further modify variables using functions the template engine provides.

The following snippet shows how filters are translated to function calls:

    ${ 42 | foo(1, 2) | bar | baz }
        ->  baz(bar(foo(42, 1, 2)))

The following filters must be provided by the implementation:

> Name | Description
> --- | ---
> date | Format the timestamp using the PHP date formatting rules. This may sound like a nonstandard way of formatting dates but it's a way very popular among template designers and also used by django.
> strftime | Format the timestamp using standard strftime rules.
> numberformat | Apply number formatting on the string. This may or may not use local specific rules.
> moneyformat | Like numberformat but for money.
> filesizeformat | Takes a number of bytes and displays it as KB/MB/GB
> format | Applies sprintf formatting on the string:: ${ "%s %2f" | format(string, float) }
> even | Is the number even?
> odd | Is the number odd?
> escape | Apply HTML escaping on a string. This also has to convert " to &quot; but leave `' unmodified.
> e | Alias for escape.
> urlencode | URL encode the string. If the second parameter is true this function should encode for path sections, otherwise for query strings.
> quotes | Escape quotes (', ", etc.)
> title | Make the string lowercase and upper case the first characters of all words.
> capitalize | Like title but capitalizes only the first char of the whole string.
> upper | Convert the string to uppercase.
> lower | Convert the string to lowercase.
> strip | Trim leading and trailing whitespace.
> lstrip | Trim leading whitespace.
> rstrip | Trim trailing whitespace.
> translate | Translate the string using either the "theme" domain or the "chyrp" domain if in Admin. (Chyrp-specific)
> translate_plural | Translate the (singular) string, or the plural string if the number passed is not 1.
> normalize | Convert all excessive whitespace (including linebreaks) into a single space.
> truncate | Truncate a string, providing ellipsis, if it is longer than the passed length. Keeps words in tact by default, but with a second boolean parameter will be strict.
> replace | Replaces the occurrence of the first argument with the second argument in the string.
> linebreaks | Convert linebreaks to <br />'s.
> camelize | Convert string to camelcase.
> strip_tags | Strip HTML from the string.
> pluralize | Return the pluralization of a string, or if a number is passed and it is 1, don't pluralize.
> sanitize | Remove special characters from a string.
> join | Concatenate the array items and join them with the string provided (or commas by default).
> split | Split a string into an array at the given breakpoints.
> first | First entry of an Array.
> offset | Entry at Array[offset].
> last | Last entry of an Array.
> reverse | Reverse the Array items.
> count | Count the number of items in an array or string characters.
> length | Alias for count.
> default | If the value is none the first argument is returned
> keys | Keys of an Array.
> items | Items of an Array.
> inspect | Dumps the variable or value.
> fallback | If the value is empty or none, return this value.
> selected | If the first argument is the same as the value, output class="selected", or selected if the second argument is true.
> option_selected | Same as selected, but for selected="selected".
> checked | Same as selected, but for checked="checked".

Additionally, if a filter is missing (say, ${ foo | bar_filter }, in Chyrp it checks for an associated Trigger filter by that filter's name.

## For Loops

Iteration works via for loops. Loops work a bit like their Python counterparts, except that they don't support multilevel tuple unpacking and that they add a new layer to the context. Thus at the end of the iteration all the modifications on the context disappear. Additionally, inside loops you have access to a special loop object which provides runtime information:

> Variable | Description
> --- | ---
> `loop.index` | The current iteration of the loop (1-indexed)
> `loop.index0` | The current iteration of the loop (0-indexed)
> `loop.revindex` | The number of iterations from the end of the loop (1-indexed)
> `loop.revindex0` | The number of iterations from the end of the loop (0-indexed)
> `loop.first` | True if this is the first time through the loop
> `loop.last` | True if this is the last time through the loop
> `loop.parent` | For nested loops, this is the loop "above" the current one

Additionally for loops can have an else section that is executed if no iteration took place.

### Example

    <ul>
    {% for user in users %}
        <li><a href="$user.href">${ user.username | escape }</a></li>
    {% else %}
        <li><em>No users found!</em></li>
    {% endfor %}
    </ul>

### Notes on Iteration

Because we have to cope with PHP too, which has problematic arrays that are neither hashmaps nor lists, we have no support for associative array iteration at all. How do you iterate over associative arrays then? Using a filter:

    {% for key, value in array | items %}
        ...
    {% endfor %}

To iterate over the keys only:

    {% for key in array | keys %}
        ...
    {% endfor %}

## If Conditions

If conditions work like like Ruby, PHP and Python, just that we use PHP keywords. Also, use elseif and not else if:

    {% if expr1 %}
        ...
    {% elseif expr2 %}
        ...
    {% else %}
        ...
    {% endif %}

## Inheritance

Template inheritance allows you to build a base "skeleton" template that contains all the common elements of your site and defines blocks that child templates can override.

Here a small template inheritance example:

    <!DOCTYPE HTML>
    <html lang="en">
      <link rel="stylesheet" href="style.css">
      <title>{% block title %}My site{% endblock %}</title>
      <div id="sidebar">
        {% block sidebar %}
         <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
         </ul>
         {% endblock %}
      </div>
      <div id="content">
         {% block content %}{% endblock %}
      </div>
    </html>

If we call that template "base.html" a "index.html" template could override it and fill in the blocks:

    {% extends "base.html" %}
    {% block title %}Foo &mdash; {% super %}{% endblock %}
    {% block content %}
        This is the content
    {% endblock %}

By using {% super %} you can render the parent's block. The template filenames must be constant strings (we don't support dynamic inheritance for simplicity) and are relative to the loader folder, not the current template.