The engine uses syntax that is similar to Liquid or Mustache, but while looking alike, they are totally different. That's because this template engine uses a lisp-like language for templates. This allows the parser to accept adding custom C and C++ functions.

By default, we ship with a standard library containing basic functionality that most projects will use close to 100% of the time.

Type system

Before we begin with the actual guide, we need to explain the type system of the templating engine. Our custom language is weakly-typed and uses strings to represent all values.

We also support 4 type hints:

  1. Normal - A regular string
  2. Function - The string contains code that can be passed to the parser. Commonly, this is used for function bodies of functions like for and if
  3. Array - The string needs to be treated as an array
  4. Map - The string needs to be treated as a map

Functions and variables

The syntax for calling a function is the following:

{{ my-function arg1 arg2 arg3 ... argn }}

Variables are also functions, which means that to get the value of a variable, you simply need to call it like a function:

{{ my-variable }}

Arrays and maps

Accessing using the at function

You can access an array at an index using the following call:

{{ at {{ my-array }} 0 }}

A map can be accessed by replacing the numeric index with a string:

{{ at {{ my-map }} my-key }}

Iterating using the for function

You can iterate an array like this:

{{ for it {{ my-array }} {{ func This is {{ it }} 
}} }}

Its arguments are like this:

  1. Name of the iterator variable
  2. The array data. If not forwarded by a variable function call, it will iterate the string
  3. A function representing the body of the function - Inside the body you can reference the iterator variables

You can iterate a map like this:

{{ for key val {{ my-map }} {{ func Key: {{ key }}
Value: {{ val }}
}} }}

Its arguments are like this:

  1. Name for the key iterator variable
  2. Name for the value iterator variable
  3. The array data. If not forwarded by a variable function call, the parser will return an error
  4. A function representing the body of the function - Inside the body you can reference the iterator variables

The list function

The list function takes a variadic list of arguments and converts it into an array variable that can be forwarded to any function that requires an array argument. It is used like this:

{{ list A B C D E F }}

The dict function

The dict function takes a variadic list of arguments and converts it into a map variable that can be forwarded to any function that requires a map argument. It is used like this:

{{ dict A B C D E F }}

Each odd element(counting from 1) of the variadic arguments list is used as the key, while each odd element is used as the value.

Note: If the function call has an odd number of arguments i.e. the last argument is a new key, not a new value, the key will be created with an empty value.

The raw function

The raw function constructs a raw string, which is not parsed. It is used like this:

{{ raw {{ for a {{ arr }}
    {{ func
        {{ a }}
    }}
}} }}

This will return the following string:

{{ for a {{ arr }}
    {{ func
        {{ a }}
    }}
}}

The comment function

You can use the comment function to write comments in the file template without being saved to the final template. It is used like this:

{{ comment This is a comment and will only be here in the template }}

The func function

The func function returns a raw string with no formatting from its arguments and marks it with the function hint. This allows other functions to use it as a callback function by passing its string data to a parser instance. It is used like this:

{{ my-func {{ func This raw string will be passed to "my-func". Call number: {{ my-func-call-num }} }} }}

As you can see, we call {{ my-func-call-num }}. As functions can add additional variables and functions to the parser, functions that accept functions can utilise this to enable the function callback to have access to certain values.

Boolean operators

The following functions implement boolean iterator constructs:

  1. == - Checks if all values of the variadic arguments list of the function are equal
  2. != - Checks if all values of the variadic arguments list of the function are not equal
  3. && - Returns the value of a boolean AND operation done on all arguments, part of the variadic arguments list of the function
  4. || - Returns the value of a boolean OR operation done on all arguments, part of the variadic arguments list of the function
  5. ! - Given a single argument with a boolean value, returns its boolean NOT value

Branches

The if function

The if functions is different by most if statements in modern programming languages. It's more like the ternary operator, without the possibility of assigning a variable to the result. It looks like this:

{{ if {{ == {{ value }} test }}
    {{ func {{ test_val }} }}
    {{ func {{ not_test_val }} }}
}}

The arguments are like this:

  1. A boolean expression
  2. A function that will be called if the previous argument is set to true
  3. A function that will be called if the previous argument is set to false

The switch function

Additionally, the switch function can be used as a switch statement in high level languages like JavaScript. The syntax looks like this:

{{ switch {{ value }} 
    test {{ func {{ test_val}} }}
    example {{ func {{ example_val }} }}
    {{ func {{ fallback_val }} }}
}}

The arguments are like this:

  1. Value to match
  2. A variadic arguments list. Arguments should be ordered so that each argument with an odd index(starting from 1) corresponds to a value, and each with an even corresponds to a function. The only exception is the last argument, which may be a function.
  3. The last argument is the fallback function.

Note 1: If the switch function is called with such arguments, that the last argument is a function that is also used to match a value, the fallback function is set to the default fallback function, which returns an empty string

The cond function

Finally, the cond function can be used as a replacement of the if statement in modern programming languages. It looks like this:

{{ cond
    {{ == {{ value }} test }}{{ func {{ test_val }} }}
    {{ == {{ value }} example }}{{ func {{ example_val }} }}
    {{ func {{ fallback_val }} }}
}}

The function takes a variadic list of arguments, where each odd index(counting from 1) corresponds to a boolean expression and each even index corresponds to a function. The only exception to this is the final argument, which should always be a function. It will be called if all other conditions fail.

Note: if the fallback function is not set, the default fallback function will be called. It returns an empty string.

Important notes

The following special functions differ in parsing behaviour:

  1. func
  2. raw
  3. comment

The differences are these:

  1. Trailing whitespace or separator characters are not removed from the last argument, so for example {{ func A B C D E }} will produce the string A B C D E
  2. There always needs to be a whitespace or separator character between the function name and the beginning of the raw string. This invalidates expressions like these: {{ func{{ my_var }}}}. Instead, a whitespace should always be added, like this: {{ func {{my_var}}}}