The priority of operations is the following, from lowest to highest:
- `+` and `-`
- `*` and `/` and `%`
#### Comparisons
- `==`: checks whether the values are equal
- `!=`: checks whether the values are different
- `>=`: true if the left value is equal or greater to the right one
- `<=`: true if the right value is equal or greater to the left one
- `>`: true if the left value is greater than the right one
- `<`: true if the right value is greater than the left one
#### Logic
- `and`: true if the left and right operands are true
- `or`: true if the left or right operands are true
- `not`: negate an expression
#### Concatenation
You can concatenate several strings/numbers/idents using the `~` operator.
```jinja2
{{ "hello " ~ 'world' ~ `!` }}
{{ an_ident ~ " and a string" ~ another_ident }}
{{ an_ident ~ another_ident }}
```
An ident resolving to something other than a string or a number will raise an error.
#### `in` checking
You can check whether a left side is contained in a right side using the `in` operator.
```jinja2
{{ some_var in [1, 2, 3] }}
{{ 'index' in page.path }}
{{ an_ident not in an_obj }}
```
Only literals/variables resulting in an array, a string and an object are supported in the right hand side: everything else
will raise an error. While in the left hand side only literals/variables resulting in a number, a string and a boolean are supported.
## Manipulating data
### Assignments
You can assign values to variables during the rendering.
Assignments in for loops and macros are scoped to their context but
assignments outside of those will be set in the global context. Furthermore, assignments
in for loop are valid until the end of the current iteration only.
```jinja2
{% set my_var = "hello" %}
{% set my_var = 1 + 4 %}
{% set my_var = some_var %}
{% set my_var = macros::some_macro() %}
{% set my_var = global_fn() %}
{% set my_var = [1, true, some_var | round] %}
```
If you want to assign a value in the global context while in a for loop, you can use `set_global`:
```jinja2
{% set_global my_var = "hello" %}
{% set_global my_var = 1 + 4 %}
{% set_global my_var = some_var %}
{% set_global my_var = macros::some_macro() %}
{% set_global my_var = global_fn() %}
{% set_global my_var = [1, true, some_var | round] %}
```
Outside of a for loop, `set_global` is exactly the same as `set`.
### Filters
You can modify variables using **filters**.
Filters are separated from the variable by a pipe symbol (`|`) and may have named arguments in parentheses.
Multiple filters can be chained: the output of one filter is applied to the next.
For example, `{{ name | lower | replace(from="doctor", to="Dr.") }}` will take a variable called name, make it lowercase and then replace instances of `doctor` by `Dr.`.
It is equivalent to `replace(lower(name), from="doctor", to="Dr.")` if we were to look at it as functions.
Calling filters on an incorrect type like trying to capitalize an array or using invalid types for arguments will result in an error.
Filters are functions with the `fn(Value, HashMap<String, Value>) -> Result<Value>` definition and custom ones can be added like so:
```rust
tera.register_filter("upper", string::upper);
```
While filters can be used in math operations, they will have the lowest priority and therefore might not do what you expect:
```css
{{ 1 + a | length }}
// is equal to
{{ (1 + a) | length } // this will probably error
// This will do what you wanted initially
{{ a | length + 1 }}
```
Tera has many [built-in filters](@/docs/_index.md#built-in-filters) that you can use.
#### Filter sections
Whole sections can also be processed by filters if they are encapsulated in `{% filter name %}` and `{% endfilter %}`
tags where `name` is the name of the filter:
```jinja2
{% filter upper %}
Hello
{% endfilter %}
```
This example transforms the text `Hello` in all upper-case (`HELLO`).
Filter sections can also contain [`block` sections](@/docs/_index.md#inheritance) like this:
```jinja2