让 treesitter 匹配类名
make treesitter match classname
我正在使用 Treesitter to parse Clojure code. Specifically I would like to distinguish between symbols, class names and 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 在 Java.lang.String
中一直看到 (new_class (classname)) (classname)
而不是 (classname)
。我想我需要某种贪婪的匹配,并且在不同的地方尝试了 prec.right()
但无济于事。我错过了什么?
我是树保姆新手,所以在处理以下内容时请考虑到这一点:)
extras
包含此语法的空格。 IIUC,这意味着如果没有在 seq
周围适当地使用 token
,树保姆将尝试解释 seq
.[=24= 中的项目之间可能出现空格的情况]
例如,对于:
seq($._dot, $._class_chars)
tree-sitter 将尝试将 $._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。当我尝试你的语法时,我没有得到与你相同的输出。
(scoped_identifier
位有点受到 tree-sitter-java 语法中同名内容的启发。)
(附带说明,ATM 似乎在树保姆 github 存储库中提出了有关树保姆的问题。那里有一些问题提到了在其他地方进行讨论的可能性,但我还没有看到任何结果。你可能会在那里得到更好的答案。)
我正在使用 Treesitter to parse Clojure code. Specifically I would like to distinguish between symbols, class names and 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 在 Java.lang.String
中一直看到 (new_class (classname)) (classname)
而不是 (classname)
。我想我需要某种贪婪的匹配,并且在不同的地方尝试了 prec.right()
但无济于事。我错过了什么?
我是树保姆新手,所以在处理以下内容时请考虑到这一点:)
extras
包含此语法的空格。 IIUC,这意味着如果没有在 seq
周围适当地使用 token
,树保姆将尝试解释 seq
.[=24= 中的项目之间可能出现空格的情况]
例如,对于:
seq($._dot, $._class_chars)
tree-sitter 将尝试将 $._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。当我尝试你的语法时,我没有得到与你相同的输出。
(scoped_identifier
位有点受到 tree-sitter-java 语法中同名内容的启发。)
(附带说明,ATM 似乎在树保姆 github 存储库中提出了有关树保姆的问题。那里有一些问题提到了在其他地方进行讨论的可能性,但我还没有看到任何结果。你可能会在那里得到更好的答案。)