1. Tree-sitter Queries 入门指南
第一次接触 Tree-sitter Queries 时,我完全被它强大的模式匹配能力震撼了。想象一下,你手里拿着一把瑞士军刀,可以精准地从代码森林中摘取任何你想要的语法果实。这就是 Queries 机制给我的第一印象。
Tree-sitter 本身是一个增量式解析器生成工具,而 Queries 则是它提供的模式匹配语言。简单来说,它允许你用类似 S-表达式的语法来描述你想要查找的代码模式。比如你想找出所有函数定义,或者提取特定类型的变量声明,都不需要手动遍历抽象语法树(AST),几行 Query 语句就能搞定。
我刚开始用的时候,发现最直观的类比就是正则表达式。正则用来匹配文本模式,而 Tree-sitter Queries 则是用来匹配语法树结构。但它的优势在于理解代码的语义结构,不会像正则那样容易误匹配。比如你想找函数调用,用正则可能会匹配到函数声明,但用 Query 就能精确区分。
2. Query 语法深度解析
2.1 基础匹配模式
最基本的 Query 模式由括号包裹的节点类型和子模式组成。举个例子,匹配 C 语言中的函数定义:
(function_definition
declarator: (function_declarator
declarator: (identifier) @function_name)) @function_def
这个模式会匹配所有函数定义节点,并捕获函数名和整个定义节点。@符号后面的名称就是我们给捕获节点起的别名,后面可以用这些别名来提取具体信息。
我第一次写这个查询时犯了个典型错误 - 忘记了字段名declarator:。结果匹配出来一堆乱七八糟的节点。后来才明白,指定字段名能让查询更精确,就像给导航加了精确坐标。
2.2 字段和匿名节点
字段名在查询中特别重要。它们就像是语法树的属性名,帮助精确定位子节点。比如在:
(assignment_expression
left: (identifier) @var_name
right: (call_expression) @call)
这里的left:和right:就是字段名,表示赋值表达式的左右两边。如果不写字段名,查询可能会匹配到不符合预期的节点。
匿名节点(如运算符)需要用双引号表示:
(binary_expression
operator: "!="
right: (null))
这个查询会匹配所有!= null的表达式。我在处理 JavaScript 代码时,这类查询特别有用。
2.3 高级查询技巧
2.3.1 通配符和否定匹配
下划线_是通配符,匹配任何节点:
(call_expression
function: (_) @func)
这个查询会匹配所有函数调用,不管调用的是什么。
否定匹配用!前缀:
(function_definition
!return_type) @void_functio

3749

被折叠的 条评论
为什么被折叠?



