Перейти к содержимому

Приоритет выражений

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

Дерево выражений

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

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

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

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

xyz-diagram.png

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

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

Приоритет выражений

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

Не запутайтесь!

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

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

TIP

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

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

Контроль приоритетов

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

xyz-diagram2.png

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

Ограничения

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

В особенности этому подвержено выражение доступа к значениям списков и карт в комбинации с бинарными операторами. Например, выражение:

JuniperBot Template
{{ list[0] + list[1] }}

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

JuniperBot Template
{{ list[0] + (list[1]) }}

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

Все права зафырканы.