Top Close Open

Template::TT3::Manual::Expressions - template expressions


Top Close Open

This is a rough draft of the documentation that will describe the expression language at the heart of TT3. It is incomplete and incorrect in places.


Top Close Open

The core syntax of the terms in the TT3 language:


10                    # integer
3.142                 # float
10e32                 # scientific
0xDEADBEEF            # hex


'single'              # single quote literal text
'Mr O\'Brien'         # backslash escape '
"double"              # double quoted text
"it was 10\" long"    # backslash escape "
"newline\nand so on"  # all the usual escape sequences
"double $var"         # variables are interpolated
"double ${foo}"       # explicit scoping
"double ${}"   # explicit scoping - see variable dotops
"double \$var"        # backslash escape $ to prevent interpolation


[10, 20]

Hash arrays

{a=>10,b=>20}         # '=>' is same as '=' in hash defs


foo                   # implicit variable
$foo                  # explicit $ variable sigil (usually same as above)
var:foo               # explicit var: variable namespace

Variable dotops
foo                   # dotops can have whitespace before them

Literal dotops


Interpolated dotops


Variable arguments (functions and object methods)

foo(a=10)             # TT params
foo(a=>10)            # regular Perl fat comma, same as foo('a',10)

Variable assignment

foo = 10              # set variable = 20          # set dotted variable
a = b = c = 10        # assignments can be chained, right associative

List expansion

a = [10,20]
b = [30,40]
c = [@a,@b]           # same as: c = [10,20,30,40]
@a                    # same as: 10, 20
@a = @b               # update contents of a with contents of b
@d = @b               # creates new list reference, same as: d = [@b]
d = @b                # @b auto-folded to list reference, same as: d = [@b]

Hash expansion

    a = { x=10, y=20 }
    b = { p=19, q=23 }
    c = { %a, %b }      # same as: c = { x=10, y=20, p=10, q=23 }

    # I *think* it should be OK to allow @hash expansion
    d = [@a]            # same as: d = ['x', 10, 'y', 20]
    c = { @a, @b }      # same as: c = { %a, %b }

    # not sure about this... it kinda makes sense but could be weird
    %a                  # export contents of a, same as: x=10, y=20


# terms can be prefixed with a namespace, either to clue the parser
# up or to access external resources

var:foo             # explicit variable, same as: $foo
template:header     # reference a template
file:example.txt    # reference a file others and your own custom namespaces...

Quote Ops (using namespaces) - note that only some of this is working

    # q: is for single quoted strings
    q:/Single Quoted Text/    # These all do *exactly* the same thing.
    q:[Single Quoted Text]    # Note in particular that q:"foo $bar" is 
    q:{Single Quoted Text}    # a *single* quoted string because of the q:
    q:    # prefix.  It just happens to be using double
    q:'Single Quoted Text'    # quotes as delimiters.  The variable embedded
    q:"Single Quoted Text"    # in the string is *not* interpolated

    # qq: is for double quoted strings
    qq:/Blah $blah/           # same as "Blah $blah"
    qq:[Blah $blah]
    qq:[Blah "$blah"]         # same as "Blah \"$blah\""
    ...and all the same delimiters as above

    # qr: is for regexen.  It can have flags on the end
    qr:/ ^ foo \s+ /sx
    qr:[ ^ foo \s+ ]sx

    # if a quotelike namespace is specified without delimiters then it 
    # consumes everything up to the next whitespace
    q:foo                           # same as 'foo', q:'foo', q:[foo] and so on                       # same as '', etc.

    # this ties in with other namespaces that don't expect delimiters
    file:example.txt                # filenames don't need to be quoted
    template:header.html            # nor do template names  # nor do URIs / URLs

    # NOTE: quoting delimiters are namespace dependent.  For example,
    # file:, template:, http: and similar accept "" and '' but not []
    # // and so on.
    file:'my file.html'
    file:[blah]                     # same as file:'[blah]'     # BEWARE!        

    # The default namespace depends on context.  In most places a word
    # is treated as a variable:
    foo                             # these are both the same

    # In other places, a template name is expected
    fill example.html               # fill (nee INCLUDE) expects template:
    fill template:example.html      # same as above

    # you can over-ride the default
    fill                # template name is in var
    fill $                   # short-hand sigil form, same as above

    # same goes for words following a dotop                         # 'bar' is a bareword
    foo.$bar                        # 'bar' is a variable
    foo.var:bar                     # same as above (but clumsy)

    # blank namespace defaults to q:
    q:foo                           # same as: 'foo'
    :foo                            # same as above


Top Close Open

All directives become expressions that can yield none or more values. That include things we traditionally think of as "statement", like "if" and "for" blocks.

Consider the following example:

Hello [% name %]

This contains two expressions. The first is a text chunk that always yields the static value 'Hello '. The second is a variable expression that yields whatever value the 'name' variable has at runtime.

A slightly more complex example:

Hello [% name or 'World' %]

We still have two expressions, but the second is now a logical 'or' expression that yields either the value of the expression on its left (the 'name' variable expression) or that of the expression on its right (the "'World'" string).

TT3 understands operator precedence.

[% a = b + c * d %]

This is parsed as:

[% a = (b + (c * d)) %]

As you would expect, you can use parens if you want different precedence.

[% a = (b + c) * d %]

Remember that everything in TT3 is an expression. For example, you can use the 'fill' command anywhere you can use a variable.

[% a = fill header %]     # fill header template and save output in 'a'

[% foo(fill header) %]    # fill header and pass output to foo()

Everything is an expression, even things like 'if' blocks.

[% a = if b; 

One thing that fall naturally out of this is generator expressions. For example, if you want a list of the numbers from 1 to 10 you can write:


Or if you prefer:

1 to 10

But what if you want the numbers 10, 20, etc., up to 100? That's easy:

for x in 1 to 10;
    x * 10;

The 'for' directive yields the values generated by its block. So if you want to capture the values and save them in a list, you can write this:

numbers = [ 
  for x in 1 to 10;
    x * 10;

Or if you prefer you can use braces to delimit blocks.

numbers = [ 
    for x in 1 to 10 {
        x * 10;

Because there's only a single expression in the 'for' block you can actually do away with the braces.

numbers = [ 
    for x in 1 to 10
        x * 10

With a single expression you can also write it in side-effect form:

numbers = [ x * 10 for x in 1 to 10 ]

In this example the 'for' command is being interpreted as an infix operator (as are '*', 'in' and 'to'). You can chain block expressions indefinitely in either direction:

numbers = [ 
    for x in 1 to 10 {      # this example has stupid logic
        if x < 5 {          # but it illustrates the point
            x * 10

Or without the braces:

numbers = [ 
    for x in 1 to 10
        if x < 5
            x * 10

Or in side effect form:

numbers = [ 
    x * 10
        if x < 5
            for x in 1 to 10

All squished up:

numbers = [ x * 10 if x < 5 for x in 1 to 10 ]

Remember you can use any commands as expressions. Here are some examples that all do the same thing: they generate a list containing the output generated from processing three separate templates.

    # explicit
    output = [ 
       fill site/header
       fill site/content
       fill site/footer

    # generate from list
    output = [ 
       fill "site/$chunk" 
          for chunk in ['header', 'content', 'body']

    # generate from split string
    output = [ 
       fill "site/$chunk" 
          for chunk in 'header content body'.split


Top Close Open

Andy Wardley


Top Close Open

Copyright (C) 1996-2009 Andy Wardley. All Rights Reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. last modified 2009-12-13 18:40:51