---
url: https://docs.juniper.bot/message-templates/advanced/precedence.md
description: Описание приоритета вычисления выражений шаблонного движка JuniperBot.
---

# Приоритет выражений { #root }

Парсер шаблонного движка — сложный механизм, состоящий из множества сгруппированных и взаимосвязанных грамматических
правил, полностью описать которые довольно сложно. В данной статье мы постараемся как можно проще объяснить, по каким
правилам и в каком порядке вычисляются те или иные выражения.

## Дерево выражений { #tree }

Любое выражение — это набор упорядоченных правил, по которым парсер шаблонного движка пытается распознать, что именно
представляет собой то или иное выражение.

Многие выражения могут состоять из подвыражений (например, правые и левые операнды бинарных выражений), которые
шаблонный движок так же пытается распознать по тому же самому набору правил.

Сложные составные выражения декомпозируются в своеобразное "дерево", где каждый узел является выражением.
У выражений и их правил есть определённые [приоритеты](#precedence), которые определяют порядок декомпозиции сложных
выражений и порядок их вычисления соответственно.

Например, для вычисления простейшего составного бинарного выражения `x * y + z` строится такое дерево с учётом приоритетов:

![xyz-diagram.png](xyz-diagram.png)

На примере выше шаблонный движок производит декомпозицию выражения от выражения в корне с наименьшим приоритетом (сложение), к
более простым выражениям в листьях с наивысшим приоритетом, как показано сплошными стрелочками.

После построения этого дерева, происходит его вычисление от листьев и узлов с наивысшим приоритетом, к корню с наименьшим
приоритетом, как показано стрелочками прочерком.

## Приоритет выражений { #precedence }

Для декомпозиции выражения шаблонный движок последовательно пытается распознать в нём конкретный тип выражения согласно
таблице ниже, начиная с самого низкого приоритета.

::: warning Не запутайтесь!
Декомпозиция выражения происходит от самого низкого приоритета к высокому для построения дерева вычисления выражения.

А вот вычисляется оно уже начиная с листьев с высоким приоритетом к корню с низшим приоритетом.
:::

::: tip Информация
Чем меньше число, тем выше приоритет выражения. Другими словами, чем ниже выражение в списке, тем ниже его приоритет.
:::

| Приоритет | Тип выражения                                                 | Пример                |
|-----------|---------------------------------------------------------------|-----------------------|
| 1         | [Переменная-идентификатор](expressions#identifiers)           | `variable`            |
| 10        | [Вызов функции или метода](functions)                         | `function(argument)`  |
| 20        | [Карта](../types/index#maps)                                  | `{ key: 'value' }`    |
| 30        | [Список](../types/index#lists)                                | `[1, 2, 3]`           |
| 40        | [Список-диапазон](../types/index#lists)                       | `[1..10]`             |
| 50        | [Строка](../types/index#literals)                             | `"hello"`, `'world'`  |
| 60        | [Число](../types/index#literals)                              | `123`, `1.5`          |
| 70        | [Логический тип](../types/index#literals)                     | `true`, `false`       |
| 80        | [Нулевая ссылка](../types/index#literals)                     | `null`                |
| 90        | `()` — выражение-скобки                                       | `(anyExpression)`     |
| 95-100    | [Унарные операторы](expressions#unary)                        | `-(-1)`, `not false`  |
| 101-140   | [Бинарные операторы](expressions#binary)                      | `2 + 2`, `x := 3 + 3` |
| 150       | [Доступ к значениям списков и карт](expressions#value-access) | `list[0]`             |
| 160       | [Оператор Элвиса](expressions#elvis)                          | `a ?: b`              |
| 170       | [Тернарный оператор](expressions#ternary)                     | `a ? b : c`           |
| 180       | [Тестовые выражения](expressions#test)                        | `1 is null`           |

## Контроль приоритетов { #precedence-control }

Для контроля приоритетов вычисления выражений необходимо использовать круглые скобки. Например, если пример выше был бы
записан как `x * (y + z)`, то дерево такого выражения выглядело бы следующим образом:

![xyz-diagram2.png](xyz-diagram2.png)

На примере выше дерево изменилось таким образом, что выражение сложения будет иметь приоритет выше, чем выражение
умножения.

## Ограничения { #limitations }

Архитектура парсера шаблонного движка не идеальна и в некоторых случаях необходимо использовать скобки, чтобы помочь ему
произвести правильную декомпозицию выражения.

В особенности этому подвержено выражение [доступа к значениям списков и карт](expressions#value-access) в комбинации с [бинарными операторами](expressions#binary). Например, выражение:

```template
{{ list[0] + list[1] }}
```

Это выражение вернёт ошибку. Из-за особенностей внутренней реализации оператора доступа, шаблонный движок не сможет
правильно декомпозировать такой шаблон, ему необходимо помочь это сделать, обернув один или оба из операндов в скобки:

```template
{{ list[0] + (list[1]) }}
```

Исправление таких мелких неудобств потребует полного пересмотра архитектуры большинства правил парсера, что в свою
очередь может привести к возникновению других проблем в других неожиданных местах, поэтому пока что мы оставляем это
поведение как есть.
