сделать treeitter соответствие имени класса

Я использую Treesitter для анализа кода Clojure. В частности, я хотел бы различать символы, имена классов и Java Interop.

Это моя грамматика:

module.exports = grammar({
    name: 'clojure',
    extras: $ => [/[\s,]/],
    rules: {
        program: $ => repeat($._anything),
        _anything: $ => choice($.symbol, $.classname, $.member_access, $.new_class),

        symbol: $ => $._symbol_chars,

        classname: $ => prec.left(3, seq($._symbol_chars, repeat1($._classname_part ))),
        _classname_part: $ => prec.right(3, seq($._dot, $._symbol_chars)),

        member_access: $ => seq($._dot, $._class_chars),
        new_class: $ => prec(2, seq( choice($.symbol, $.classname), $._dot)),

        _dot: $ => /\.{1}/,
        _symbol_chars: $ =>   /[a-zA-Z\*\+\!\-_\?][\w\*\+\!\-\?\':]*/,
        _class_chars: $ => /[a-zA-Z_]\w*/
    }
})

Я ожидал

foo
java.lang.String
.toUpperCase
java.awt.Point.

быть проанализированным

(program (
    (symbol)
    (classname)
    (member_access)
    (new_class (classname)))

Но Treesitter продолжает видеть (new_class (classname)) (classname) вместо того (classname) за Java.lang.String. Я полагаю, что мне нужно какое-то жадное сопоставление, и я попробовал prec.right()в разных местах безрезультатно. Что мне не хватает?

1 ответ

Решение

Я новичок в садоводстве, поэтому, пожалуйста, примите это во внимание при обработке следующего:)

extrasсодержит пробел для этой грамматики. IIUC, это означает, что если не использоватьtoken около seq соответственно, tree-sitter попытается учесть случаи, когда пробелы могут возникать между элементами в seq.

Например, для:

seq($._dot, $._class_chars)

садовник будет пытаться рассматривать как действительный $._dot а также $._class_charsразделенные пробелом. Но IIUC, который в Clojure не обязательно эквивалентен случаю, когда они не разделены пробелами.

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

Ниже приведен пример для обработки 4 предоставленных тестовых случаев. Хотя то, что анализируется, в точности различается, все же можно провести соответствующие различия, AFAICT.

const JAVA_ID = /[a-zA-Z_]\w*/;

module.exports = grammar({

    name: 'clojure',

    extras: $ =>
        [/[\s,]/],

    rules: {
        program: $ =>
            repeat($._anything),

        _anything: $ =>
            choice($.symbol,
                   $.member_access,
                   $.new_class),

        symbol: $ =>
            choice($._symbol_chars,
                   $.scoped_identifier),

        // XXX: approximate, see: https://clojure.org/reader
        _symbol_chars: $ =>
            /[a-zA-Z\*\+\!\-_\?][\w\*\+\!\-\?\':]*/,

        // XXX: except $ can be used too for inner classes?
        scoped_identifier: $ =>
            token(seq(JAVA_ID,
                      repeat(seq('.', JAVA_ID)))),

        // e.g. .toUpperCase
        member_access: $ =>
            token(seq('.',
                      JAVA_ID,
                      repeat(seq('.', JAVA_ID)))),

        // e.g. java.lang.String.
        new_class: $ =>
            token(seq(JAVA_ID,
                      repeat(seq('.', JAVA_ID)),
                      '.')),

    }
});

function sep1 (rule, separator) {
    return seq(rule, repeat(seq(separator, rule)));
}

Обратите внимание, что версия tree-sitter-cli может иметь значение - я использовал 0.16.4. Когда я попробовал вашу грамматику, я не получил того же результата, что и вы.

(The scoped_identifier bit был вдохновлен чем-то с таким же названием из грамматики tree-sitter-java.)

(Кстати, банкомат, похоже, что вопросы о tree-sitter задаются в репозитории tree-sitter на github. Были некоторые проблемы, упоминающие возможность других мест для обсуждения, но я не видел, чтобы что-то произошло еще. Там вы можете получить более точные ответы.)

Другие вопросы по тегам