simple-templates- A basic template language for the Simple web framework

Safe HaskellTrustworthy




A simple templating system with variable substitution, function invokation, for loops and conditionals. Most callers should use compileTemplate and invoke the template with renderTemplate. E.g.:

 let myTemplate = compileTemplate "Hello, $@$!"
 print $ renderTemplate myTemplate mempty "World"


Language Description

A template may contain plain-text, which is reproduced as is, as well as blocks of code, escaped by surrounding with dollar-signs ($), for variable expansion, function invokation, conditionals and loops. For example, given a global variable "answer" with the value 42,

 The answer to the universe is $answer$.

would expand to

 The answer to the universe is 42.

Since the dollar-sign is used to denote code sections, it must be escaped in plaintext sections by typing two dollar-signs. For example, to reproduce the lyrics for Bonzo Goes to Bitburg, by The Ramones:

 Shouldn't wish you happiness,
 wish her the very best.
 $$50,000 dress
 Shaking hands with your highness


Bools, Numbers, Strings, Arrays and Null can be typed as literals.

  • Bools are the lower-case "true" and "false"
  • Numbers are simply typed as decimals
 Pi is approximately $3.14159$
  • Strings are surrounded by double-quotes ("). Double-quotes inside a string can be escaped by proceeding it with a backslash (\"), however backslashes themselves do not need to be escaped:
 And then, Dr. Evil said: $"Mini Me, stop humping the \"laser\"."$
  • Arrays are surrounded by square-brackets ([ ]) and elements are comma separated. Elements can be literals, variables or function invokations, and do not have to be the same type:
 $["Foo", 42, ["bar", "baz"], length([1, 2, 3, 6])]$
  • Null is type as the literal null (in lower case):

Variable substitution

Templates are evaluated with a single global variable called @. For example, you can refernce the global in your template like so:

 The value in my global is $@$.

If the global is an Object, it can be indexed using dot-notation:

 The Sex Pistols' bassist was $$

In this case, you may also discard the @ global reference and simply name the field in the global object, for example:

 Field 'foo' is $foo$.
 Field 'bar.baz' is $bar.baz$.

Strings, Numbers and Bools are meaningful when evaluated to text in a template, while Objects, Arrays and Nulls simply render as strings representing their types (e.g. "[object]"). However, all types can be used as arguments to functions, or in conditionals and loops.

Function Invokation

Functions are invoked with similar syntax to imperative languages:

 $myfunc(arg1, arg2, arg3)$

where arguments can be literals, variables or other function calls -- basically anything that can be evaluated can be an argument to a function. Function names are in a separate namespace than variables, so there can be a function and variable both named foo and they are differentiated by their use. For example:


is a variable expansion, whereas


is a function invokation.


Branching is supported through the common if statement with an optional else branch. Conditions can be any expression. false and null are evaluated as false, while everything else is evaluated as true.

if blocks are surround by an if-statement and and endif, each surrounded separately by dollar signs. Optionally, the else branch is declared by with "$else$". The blocks themselves are templates and may contain regular text as well as evaluable expressions.

 Should I stay or should I go?
 Trouble will be $trouble$.
 Trouble will be $double(trouble)$

For Loops

For loops iterate over collections, setting a variable name to one element in the collection for each iteration of the loop. Collections are usually Arrays, however non-false expressions (e.g., Strings and Numbers) are treated as collections with one element. A loop starts with a for-statement surrounded by dollar-signs and end with an "$endfor$":

 <h1>The Clash</h1>
 $for(member in band)$
 <li>$$ played the $member.instrument$</li>

There is also an optional "$sep$" (for separator) clause, which is rendered between iterations. So if I have a collection with three items, the sep clause will be rendered after the first and second, but not third elements:

 <h1>Grocery list</h1>
 $for(item in groceries)$
 $item.quantity$ $$(s).

Will render something like:

 <h1>Grocery list</h1>
 2 MC(s).
 1 DJ(s)




:: FunctionMap

Mapping of functions accessible to the template

-> Value

The global Object or Value

-> AST 
-> Value