【问题标题】:make treesitter match classname使treesitter匹配类名
【发布时间】:2020-05-25 13:17:34
【问题描述】:

我正在使用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() 无济于事。我错过了什么?

【问题讨论】:

    标签: java parsing clojure treesitter


    【解决方案1】:

    我是一个树保姆新手,所以在处理以下内容时请考虑到这一点:)

    extras 包含此语法的空格。 IIUC,这意味着如果一个人没有在seq 周围适当地使用token,tree-sitter 将尝试考虑seq 中的项目之间可能出现空格的情况。

    例如,对于:

    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 似乎有关 tree-sitter 的问题正在 tree-sitter github 存储库中提出。那里有一些问题提到了其他地方进行讨论的可能性,但我还没有看到任何事情都还没发生。你可能会在那里得到更好的答案。)

    【讨论】:

    • 我一直缺少的是 token 的使用。这是我一直在寻找的答案。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 2018-10-07
    • 2012-11-05
    相关资源
    最近更新 更多