Skip to content

Operators and Expressions

Expressions are the logic building blocks, they allow you to express a value. From the basic constants to binary and ternary operations, expressions give the power to specify a value.

Identifiers

Identifiers are one of the simplest expressions. They represent variables, properties, method and function names. Identifiers can only contain alphanumeric (Latin) characters, underscores, digits, however they cannot start with digits.

Keywords

Template Engine has a set of reserved keywords used for building complex constructs as part of tags and other expressions. Although they are valid identifiers, they can't be used as identifiers.

Here is the list of the reserved keywords:

setin
globalas
ifdo
elseifverbatim
elsefilter
endifendfilter
fornull
endforis
truenot
falsewith
emptyrequire
returnreturning
includemacro

Access Expressions

List or Map Values

In order to access either a list element or map value, Template Engine comes with the value access expression where you use a list element index or map key, defined in square braces []. Note that list elements index always starting at zero.

JuniperBot Template
{{ list[0] }}
{{ map["key1"] }}

WARNING

List or Map Values Access expressions in combination with binary operators are very sensitive to parentheses.

This is a technical limitation of the template engine parser architecture, you can find more details about it here.

Properties and Methods

In order to access an object property or invoke its method, the selection operator . (dot) is used. You can find available properties and methods in the Data Types and Variables articles.

JuniperBot Template
{{ guild.name }}
{{ guild.getMember(247734710682255361) }}

Selection operator can also be used for maps as well to get the value represented by key, if this key is valid identifier:

JuniperBot Template
{{ map.key1 }}

Complex Expressions

Constants, variables and other expressions can be combined into more complex expressions by using operators. Operator precedence determine the order in which the operations in an expression are performed.

These operators include the following groups:

  1. Unary Operators;
  2. Binary Operators;
  3. Ternary Operator.

Order of Evaluation

In an expression with multiple operators, the operators with higher precedence are evaluated before the operators with lower precedence. Operators of the same precedence are evaluated in lexical order.

You can use parentheses to change the order of evaluation imposed by operator precedence.

If you want to know more about expressions precedences, check Expressions Precedence article.

TIP

The lower the number, the higher the precedence and the earlier it is evaluated.

Unary Operators

Unary operators by definition only need one argument, Template Engine comes with only two built in unary operators, they are not and -.

SymbolDescriptionPrecedenceExample
-Switches the signal95-(-1) outputs 1
notNegates the input100not false outputs true;
not true outputs false

Binary Operators

Template Engine comes with several built-in binary operators:

TIP

The lower the number, the higher the precedence and the earlier it is evaluated.

SymbolPrecedenceDescriptionПример
.101Access inner properties of objectsmember.id outputs member id
^103Takes base number to to the power of exponent2 ^ 3 outputs 8
*105Multiplies two values2.2 * 2.2 outputs 4.84
**105Multiplies the integer part of two values2.2 ** 2.2 outputs 4
/105Divides two values5.0 / 2.0 outputs 2.5
//105Divides the integer part of two values5.0 // 2.0 outputs 3
%105Gets the integer division remainder5 % 2 outputs 1
+110Sums two values5 + 2 outputs 7
-110Subtracts two values5 - 2 outputs 3
~112Concatenates two strings"5" ~ "2" outputs "52"
<115Compares two values, checking whether the first is lower than the second1 < 2 outputs true 1 < 1 outputs false
<=115Compares two values, checking whether the first is lower or equal than the second2 <= 2 outputs true 2 < 1 outputs false
>115Compares two values, checking whether the first is higher than the second2 > 1 outputs true 2 > 2 outputs false
>=115Compares two values, checking whether the first is higher or equal than the second2 >= 2 outputs true 2 >= 3 outputs false
in115Checks whether the second value contains the first one5 in [2] outputs false
==120Compares two values, checking whether they are equal or nottrue == false outputs false false == false outputs true
!=120Compares two values, checking whether they are different or nottrue != false outputs true false != false outputs false
and125Conjunction boolean operatortrue and false outputs false true and true outputs true
or125Disjunction boolean operatortrue or false outputs true false or false outputs false
|130Uses the first argument as parameter for the second argument. Note that, composition forces the second argument to be a function-5 | abs outputs 5
:=140Calculates and returns second value, assigning it to the variable in the first operand. More details.result := 1 + 2 outputs 3, assigning it as result variable

Assignment Operator

Assignment Operator (affectionately known as "the walrus operator" :=) is a binary operator that lets you assign value to variable and return it at the same time.

JuniperBot Template
{{ <variable> := <expression> }}

The walrus calculates the value of the expression, assigns it to the specified variable and returns the same value.

JuniperBot Template
{{ result := 1 + 2 }}
{{ result }}

Previous example will return "3" twice. First one is the result of expression calculation and second one is the value of result variable that has been updated by this assignment expression.

This operator is very useful to make your code look better and shorter. For example, let's take a simple template using set tag to assign a value to variable:

JuniperBot Template
{% set amount = 5 %}
{% if amount > 0 %}
Daniel has {{ amount }} apples!
{% endif %}

This template can be simplified:

JuniperBot Template
{% if (amount := 5) > 0 %}
Daniel has {{ amount }} apples!
{% endif %}

Assignment Precedence

As you can see on the table above, the Assignment Operator has the lowest precedence along other binary operators and this must be taken into account.

If previous example would have an expression written like amount := 5 > 0, the amount value would be true, not 5, because comparing operator has the higher precedence so it calculates first. This is why we must use parentheses to isolate assignment operator.

Assignment Operator itself can't make a global variables, but if specified variable does already exist and is global, the assignment operator will update its value and keep it global.

Ternary Operator

Template Engine only contains one ternary operator. It allows to fork the logic based on a boolean expression, as exemplified below:

JuniperBot Template
{{ expr ? 1 : 2 }}

Such expression will output 1 if the variable expr is true, or 2 if the variable is false.

Elvis Operator

Template Engine supports Elvis operator that returns its first operand if that operand evaluates to a true value according Type Convert, and otherwise evaluates and returns its second operand.

JuniperBot Template
{{ <expression A> ?: <expression B> }}

This operator is very useful to return a "default" value for expressions.

TIP

By its nature, the Elvis Operator should be binary, but from the perspective of the template engine's rules, it is placed in a separate group, which precedence is even lower than the entire group of binary expressions, but higher than the Ternary Operator.

Test Expressions

Test expressions are a complex predicate construct, they return a boolean value as result.

NameDescriptionExample
NullChecks whether a value is null or not1 is null outputs false
DivisibleChecks if a value is divisible by another2 is divisible by 1 outputs true
Same AsChecks whether two objects are strictly equal by their reference1 is same as (2) outputs false
Function basedThis checks the function result by invoking it with the value as argument.4 is defined outputs true;
'test' is number outputs false.
Is NotAll test constructs listed before can be negated with the is not constructor.4 is not defined outputs false

"Same As" Test Expression

This expression tests for the same object by reference, not just their value. For example:

JuniperBot Template
{{ 1 is same as (1) }}

This will print false. Yes, they are both number 1, but they are different instances of same number having different reference internally. Now check this:

JuniperBot Template
{% set value = 1 %}
{% set other = value %}
{{ value is same as (other) }}

This will print true because those both value and other variables have the same reference to the same number.

It works for null though:

JuniperBot Template
{{ null is same as (null) }}

This will print true because null reference is always the same.

All rights sniffed.