Курс языка программирования Raku / Регулярные выражения и грамматики / Грамматики / Дерево разбора, make и made

make и made

Вместо того чтобы потом выуживать значения из дерева, можно прикрепить значение к совпадению прямо во время разбора. В тело токена можно встроить блок кода — внутренний { … }, записанный среди шаблона, — который выполняется, как только сопоставление до него доходит. Внутри такого блока функция make сохраняет значение на текущем совпадении:

grammar OneNum {
    token TOP    { <number> { make $<number>.Int } }
    token number { \d+ }
}

Когда TOP совпадает, выполняется внутренний блок { make $<number>.Int } — внешние фигурные скобки здесь просто тело токена — и сохраняет на совпадении целое число. Прочитать его обратно можно потом через made (или его синоним .ast):

say OneNum.parse('42').made; # 42

Поскольку мы сохранили $<number>.Int, значение, которое возвращает made, — это настоящий Int, само число, а не объект совпадения:

say OneNum.parse('42').made + 1; # 43

Заметьте, что именно это + 1 дало бы 43 и без .Int, ведь в арифметике совпадение приводится к числу по своим цифрам. Смысл вызова .Int в том, что сохранённое значение действительно является числом, — а это как раз то, что нужно, когда оно попадает в структуру данных или передаётся дальше, а не остаётся сырым совпадением.

Сохранять можно что угодно — число, строку, массив, объект. Токен может и объединить значения, которые сделали его подтокены. Например, сложить два захваченных числа:

grammar Sum {
    token TOP { <a> '+' <b> { make $<a>.Int + $<b>.Int } }
    token a   { \d+ }
    token b   { \d+ }
}

say Sum.parse('2+3').made; # 5

make и made — это мост от «совпало» к «вот его смысл». Встроенные блоки работают, но смешивают шаблон с логикой; следующий раздел переносит эту логику в отдельный класс действий.

Практика

Пройдите 1 тест по содержанию этой темы.

Навигация по курсу

Тест — Дерево совпадения   |   Тест — make и made


💪 Или перейдите сразу к упражнениям этого раздела.