сделать 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. Были некоторые проблемы, упоминающие возможность других мест для обсуждения, но я не видел, чтобы что-то произошло еще. Там вы можете получить более точные ответы.)