38.3 Извлечение узлов

Вот некоторые термины и соглашения, которые мы используем при описании функций tree-sitter.

Узел в синтаксическом дереве охватывает некоторую часть текста программы в буфере. Мы говорим, что узел «меньше» или «больше» другого, если он охватывает, соответственно, меньшую или большую часть текста буфера, чем другой узел. Поскольку узлы, которые находятся глубже («ниже») в дереве, являются потомками узлов, которые находятся «выше» в дереве, из этого следует, что нижний узел всегда будет меньше, чем узел, находящийся выше в иерархии узлов. Узел, расположенный выше в синтаксическом дереве, содержит один или несколько меньших узлов в качестве своих потомков и поэтому охватывает большую часть текста буфера.

Когда функция не может найти узел, она возвращает nil. Для удобства все функции, которые принимают узел в качестве аргумента и возвращают узел, также принимают аргумент-узел, равный nil, и в этом случае просто возвращают nil.

Узлы не обновляются автоматически при изменении связанного буфера, и нет способа обновить узел после его извлечения. Использование устаревшего узла вызывает ошибку treesit-node-outdated.

Извлечение узлов из синтаксического дерева

Функция: treesit-node-at pos &optional parser-or-lang named

Эта функция возвращает листовой узел в позиции буфера pos. Листовой узел — это узел, у которого нет дочерних узлов.

Эта функция пытается вернуть узел, чей диапазон покрывает pos: начальная позиция узла меньше или равна pos, а конечная позиция узла больше или равна pos.

Если диапазон ни одного листового узла не покрывает pos (например, pos находится в пробеле между двумя листовыми узлами), эта функция возвращает первый листовой узел после pos.

Наконец, если нет листового узла после pos, возвращается первый листовой узел перед pos.

Если parser-or-lang является объектом парсера, эта функция использует этот парсер; если parser-or-lang является языком, эта функция использует первый парсер для этого языка в текущем буфере или создаёт его, если ни одного нет; если parser-or-lang равен nil, эта функция пытается определить язык в pos вызовом treesit-language-at (см. Разбор текста на нескольких языках).

Если эта функция не может найти подходящий узел для возврата, она возвращает nil.

Если named не равен nil, эта функция ищет только именованные узлы (см. именованный узел).

Пример:

;; Найти узел в точке в синтаксическом дереве парсера C.
(treesit-node-at (point) 'c)
  ⇒ #<treesit-node (primitive_type) в 23-27>
Функция: treesit-node-on beg end &optional parser-or-lang named

Эта функция возвращает наименьший узел, который покрывает область текста буфера между beg и end. Другими словами, начало узла находится до или на beg, а конец узла — на end или после него.

Внимание: вызов этой функции на пустой строке, которая не находится внутри ни одной конструкции верхнего уровня (определение функции и т.п.), скорее всего, вернёт корневой узел, потому что корневой узел является наименьшим узлом, покрывающим эту пустую строку. В большинстве случаев вы захотите использовать treesit-node-at.

Если parser-or-lang является объектом парсера, эта функция использует этот парсер; если parser-or-lang является языком, эта функция использует первый парсер для этого языка в текущем буфере или создаёт его, если ни одного нет; если parser-or-lang равен nil, эта функция пытается определить язык в beg вызовом treesit-language-at.

Если named не равен nil, эта функция ищет только именованный узел (см. именованный узел).

Функция: treesit-parser-root-node parser

Эта функция возвращает корневой узел синтаксического дерева, созданного парсером parser.

Функция: treesit-buffer-root-node &optional language

Эта функция находит первый парсер для language в текущем буфере или создаёт его, если ни одного нет, и возвращает корневой узел, созданный этим парсером. Если language опущен, используется первый парсер в списке парсеров. Если подходящий парсер не найден, возвращает nil.

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

Извлечение узлов из других узлов

По родству

Функция: treesit-node-parent node

Эта функция возвращает непосредственного родителя node.

Если node находится глубже 1000 уровней в дереве разбора, возвращаемое значение не определено. В настоящее время возвращается nil, но это может измениться в будущем.

Функция: treesit-node-child node n &optional named

Эта функция возвращает n-го потомка node. Если named не равен nil, учитываются только именованные узлы (см. именованный узел).

Например, в узле, представляющем строку "text", есть три дочерних узла: открывающая кавычка ", текст строки text и закрывающая кавычка ". Среди этих узлов первый потомок — открывающая кавычка ", а первый именованный потомок — текст строки.

Функция возвращает nil, если нет n-го потомка. n может быть отрицательным, например, −1 означает последнего потомка.

Функция: treesit-node-children node &optional named

Эта функция возвращает всех потомков node в виде списка. Если named не равен nil, извлекаются только именованные узлы.

Функция: treesit-node-next-sibling node &optional named

Эта функция находит следующего брата node. Если named не равен nil, находит следующего именованного брата.

Функция: treesit-node-prev-sibling node &optional named

Эта функция находит предыдущего брата node. Если named не равен nil, находит предыдущего именованного брата.

По имени поля

Чтобы упростить анализ синтаксического дерева, многие языковые грамматики присваивают имена полей дочерним узлам (см. имя поля). Например, узел function_definition может иметь потомка declarator и потомка body.

Функция: treesit-node-child-by-field-name node field-name

Эта функция находит потомка node, имя поля которого равно field-name (строка).

;; Получить потомка с именем поля "body".
(treesit-node-child-by-field-name node "body")
  ⇒ #<treesit-node (compound_statement) в 45-89>

По позиции

Функция: treesit-node-first-child-for-pos node pos &optional named

Эта функция находит первого потомка node, который выходит за позицию буфера pos. «Выходит за» означает, что конец дочернего узла больше или равен pos. Эта функция ищет только непосредственных потомков node и не заглядывает в его внуков. Если named не равен nil, ищет первого именованного потомка (см. именованный узел).

Функция: treesit-node-descendant-for-range node beg end &optional named

Эта функция находит наименьший дочерний узел node, который покрывает область текста между позициями beg и end. Она аналогична treesit-node-at. Если named не равен nil, ищет наименьший именованный потомок.

Поиск узла

Функция: treesit-search-subtree node predicate &optional backward all depth

Эта функция обходит поддерево node (включая сам node), в поисках узла, для которого predicate возвращает не nil. predicate — это регулярное выражение, которое сопоставляется с типом каждого узла, или функция-предикат, которая принимает узел и возвращает не nil, если узел подходит. predicate также может быть символом-вещью или определением вещи (см. Определяемые пользователем «Вещи» и навигация). Использование неопределённой вещи не вызывает ошибку, функция просто возвращает nil.

Эта функция возвращает первый подходящий узел или nil, если ни один не соответствует predicate.

По умолчанию эта функция обходит только именованные узлы, но если all не равен nil, она обходит все узлы. Если backward не равен nil, обход выполняется в обратном направлении (т.е. при спуске по дереву сначала посещается последний потомок). Если depth не равен nil, это должно быть число, ограничивающее обход дерева заданным количеством уровней вглубь. Если depth равен nil, по умолчанию используется 1000.

Функция: treesit-search-forward start predicate &optional backward all

Как и treesit-search-subtree, эта функция также обходит дерево разбора и сопоставляет каждый узел с predicate (кроме start), где predicate может быть регулярным выражением или функцией-предикатом. predicate также может быть символом-вещью или определением вещи (см. Определяемые пользователем «Вещи» и навигация). Использование неопределённой вещи не вызывает ошибку, функция просто возвращает nil.

Для дерева, показанного ниже, где start отмечен как ‘S’, эта функция выполняет обход в порядке нумерации от 1 до 12:

              12
              |
     S--------3----------11
     |        |          |
o--o-+--o  1--+--2    6--+-----10
|  |                  |        |
o  o                +-+-+   +--+--+
                    |   |   |  |  |
                    4   5   7  8  9

Обратите внимание, что эта функция не обходит поддерево start и всегда сначала обходит листовые узлы, прежде чем двигаться вверх.

Как и treesit-search-subtree, эта функция по умолчанию ищет только именованные узлы, но если all не равен nil, она ищет все узлы. Если backward не равен nil, поиск выполняется в обратном направлении.

В то время как treesit-search-subtree обходит поддерево узла, эта функция начинается с узла start и обходит каждый узел, который идёт после него в порядке позиций в буфере, т.е. узлы с начальными позициями больше конечной позиции start.

В дереве, показанном выше, treesit-search-subtree обходит узел ‘S’ (start) и узлы, отмеченные o, тогда как эта функция обходит узлы, отмеченные цифрами. Эта функция полезна для ответа на вопросы типа «какой первый узел после start в буфере удовлетворяет некоторому условию?»

Функция: treesit-search-forward-goto node predicate &optional start backward all

Эта функция перемещает точку в начало или конец следующего узла после node в буфере, который соответствует predicate. Если start не равен nil, останавливается в начале, а не в конце узла.

Эта функция гарантирует, что возвращаемый совпавший узел делает прогресс в смысле позиции в буфере: начальная/конечная позиция возвращаемого узла всегда больше, чем у node.

Аргументы predicate, backward и all такие же, как и в treesit-search-forward.

Функция: treesit-induce-sparse-tree root predicate &optional process-fn depth

Эта функция создаёт разреженное дерево из поддерева root.

Она берёт поддерево под root и прочёсывает его, оставляя только узлы, которые соответствуют predicate. Как и в предыдущих функциях, predicate может быть строкой-регулярным выражением, сопоставляемой с типом каждого узла, или функцией, которая принимает узел и возвращает не nil, если он подходит. predicate также может быть символом-вещью или определением вещи (см. Определяемые пользователем «Вещи» и навигация). Использование неопределённой вещи не вызывает ошибку, функция просто возвращает nil.

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

    a                 a              a
    |                 |              |
+---+---+         +---+---+      +---+---+
|   |   |         |   |   |      |   |   |
b   1   2         b   |   |      b   c   d
    |   |     =>      |   |  =>      |
    c   +--+          c   +          e
    |   |  |          |   |
 +--+   d  4       +--+   d
 |  |              |
 e  5              e

Если process-fn не равен nil, вместо возврата совпавших узлов эта функция передаёт каждый узел в process-fn и использует возвращённое значение вместо узла. Если не равен nil, depth ограничивает количество уровней спуска от root. Если depth равен nil, по умолчанию используется 1000.

Каждый узел в возвращаемом дереве выглядит как (tree-sitter-node . (child …)). tree-sitter-node корня этого дерева будет nil, если root не соответствует predicate. Если ни один узел не соответствует predicate, функция возвращает nil.

Дополнительные вспомогательные функции

Функция: treesit-node-get node instructions

Это вспомогательная функция, которая объединяет несколько функций доступа к узлам в цепочку. Например, чтобы получить текст родителя node, его следующего брата, второго потомка:

(treesit-node-get node
   '((parent 1)
    (sibling 1 nil)
    (child 1 nil)
    (text nil)))

instruction — это список ИНСТРУКЦИЙ вида (fn arg...). Поддерживаются следующие fn:

(child idx named)

Получить idx-го потомка.

(parent n)

Подняться к родителю n раз.

(field-name)

Получить имя поля текущего узла.

(type)

Получить тип текущего узла.

(text no-property)

Получить текст текущего узла.

(children named)

Получить список потомков.

(sibling step named)

Получить n-го предыдущего/следующего брата, отрицательный step означает предыдущего брата, положительный — следующего.

Обратите внимание, что такие аргументы, как named и no-property, не могут быть опущены, в отличие от их оригинальных функций.

Функция: treesit-filter-child node predicate &optional named

Эта функция находит непосредственных потомков node, которые удовлетворяют predicate.

Функция predicate принимает узел в качестве аргумента и должна возвращать не nil, чтобы указать, что узел должен быть сохранён. Если named не равен nil, эта функция рассматривает только именованные узлы.

Функция: treesit-parent-until node predicate &optional include-node

Эта функция многократно находит родителей node и возвращает родителя, удовлетворяющего predicate. predicate может быть либо функцией, принимающей узел и возвращающей t или nil, либо регулярным выражением, сопоставляемым с именами типов узлов, либо другими допустимыми предикатами, описанными в treesit-thing-settings. Если ни один родитель не удовлетворяет predicate, функция возвращает nil.

Обычно эта функция смотрит только на родителей node, но не на сам node. Однако если include-node не равен nil, эта функция возвращает node, если node удовлетворяет predicate.

Функция: treesit-parent-while node predicate

Эта функция поднимается по дереву, начиная с node, и продолжает это делать, пока узлы удовлетворяют predicate — функции, которая принимает узел в качестве аргумента. То есть эта функция возвращает самого высокого родителя node, который всё ещё удовлетворяет predicate. Обратите внимание, что если node удовлетворяет predicate, но его непосредственный родитель — нет, возвращается сам node.

Функция: treesit-node-top-level node &optional predicate include-node

Эта функция возвращает самого высокого родителя node, который имеет тот же тип, что и node. Если такого родителя нет, возвращается nil. Таким образом, эта функция также полезна для проверки, является ли node узлом верхнего уровня.

Если predicate равен nil, эта функция использует тип node для поиска родителя. Если predicate не равен nil, эта функция ищет родителя, удовлетворяющего predicate. Если include-node не равен nil, эта функция возвращает node, если node удовлетворяет predicate.