Expressions

One of the more powerful features of Carrot is it's support for expressions. Many template languages support variables with just complicated regular expressions, which means you end up with weird, complicated patterns for doing anything with them (see all the filters in Jinja2, for example).

In Carrot, everything is parsed with a proper recursive-decent parser, we get much more natural syntax for dealing with expressions. Below are some examples of things that are supported in Carrot's model:

Basic arithmetic
a + b
foo + 1
bar * 3.4
a + (foo * 3) - 2
Boolean operations
x == 2
foo <= bar
bar != 0
x > 0 || y > 0
Ternary operator
a == 0 ? "zero" : "non-zero"
foo ? foo : "default"

The ternary operator should be familiar to anybody coming from Java. It evaluates the term before the ?, and if true evaluates the term before the :, if false it evaluates to the term after the :.

You can also use the ternary operator to provide default values when querying a map for a value.

Elvis operator
foo ?: "default"

The elvis operator tests the left-hand side of the expression, and returns it if it's true-ish -- otherwise it returns the right-hand side.

The elvis operator is essentially short-hand for {{foo ? foo : "default"}}

Accessor methods
foo.bar.baz
foo["bar"]
foo[bar.baz].blah

The rules for querying accessor methods are fairly simple. In the case of foo.bar, we will first look for a field on foo call "bar", then we will look for a method on foo called "getBar". If foo is a Map, we will attempt to call Map.get, with the string "bar".

In the case of foo[bar], we will first evaluate the variable bar, and use that value to query foo. Note that whether accessed via . or via [], the rules are actually the same (that is, we'll still look for a field with the name that bar evaluates to).

Method calls
foo.bar()
foo.bar(x, y)

Method calls work exactly as you'd expect. In the case of foo.bar(x, y), we first try to evaluate x and y. Then we look for a method on foo named "bar", which takes two parameters. The expression evaluates to the return value of the bar method.