Tree-sitter如何正确使用catch-all规则,使其仅在其他规则匹配失败后触发
问题根因
该匹配异常由两个规则配置缺陷共同导致:
uninomial的两个可选分支优先级相同,Tree-sitter默认优先选择长度更短的匹配路径,会直接将首个Bubo识别为uninomial,剩余内容直接走tail兜底。tail兜底规则未显式设置低于业务规则的优先级,解析器不会优先尝试更长的uninomial匹配,直接选择uninomial + tail的短路径完成解析。
解决方案
通过显式配置优先级即可实现预期的兜底逻辑:
- 给
uninomial中带亚属的长匹配分支设置更高优先级,强制解析器优先尝试匹配该分支 - 给
tail规则设置最低优先级,仅当所有前置业务规则都匹配失败时才触发兜底
修改后的完整语法如下:
const terminator = '\n'; module.exports = grammar({ name: 'sciname', rules: { source_file: ($) => repeat($._sci_name), _sci_name: ($) => seq($.uninomial, optional($.tail), terminator), _uninomial: ($) => /[A-Z][a-z]+/, uninomial: ($) => choice( prec(1, seq($.genus, $.subgenus)), // 长匹配分支优先级更高 $._uninomial ), genus: ($) => $._uninomial, subgenus: ($) => seq('(', $._uninomial, ')'), tail: ($) => prec.low(/[^\n]+/), // 兜底规则优先级最低 }, });
如果后续新增更多uninomial的扩展匹配规则,仍出现优先级冲突,可以新增conflicts声明,让解析器主动尝试所有可能的匹配路径:
module.exports = grammar({ // ...其他配置不变 conflicts: ($) => [ [$.uninomial, $.tail] ] })
修改后你的测试用例即可输出预期的解析结果:(source_file (uninomial (genus) (subgenus)))
内容的提问来源于stack exchange,提问作者dimus
相关产品推荐
相关产品推荐

