树上看护新手指南
浏览大量或复杂的代码可能具有挑战性,但Tree-sitter可以提供帮助。
关键背景知识
树上看护者
Tree-sitter根据语言生成解析器,并提供引擎所见代码的洞察。它将杂乱的代码编织成一张清晰、结构化的图谱,揭示不同部分之间的关系。这张图谱被称为抽象语法树 (AST),它就像一个可视化的蓝图,使复杂的代码更易于理解。
抽象语法树(AST)
AST(抽象语法树)将代码分解为基本元素——变量、函数和表达式——并展示它们之间的相互作用,类似于家谱,每个人通过血缘关系相互联系。树的根代表整个程序,分支代表不同的部分。正如家谱阐明了关系一样,AST 使代码连接清晰可见。
更正式地说,它是源代码的图形表示,主要用于编译器读取代码并生成目标二进制文件。
您可以在这里使用您的代码,并将其可视化为 AST。
编码时间!
示例代码
让我们看看 AST 可视化和 Tree-sitter 如何为以下 Python 代码工作!
def greet(name):
print("Hello, " + name + "!")
在构建抽象语法树 (AST) 时,函数定义被指定为根节点,“greet” 和 “name” 构成其直系后代或子节点,以此来表明函数及其组件之间的层级关系。随后,print 语句作为函数定义的另一个子节点被集成到 AST 中,其内部语法结构被进一步细分,以表示操作及其操作数,如下图所示:
上面形成的 AST 可以可视化为如下树:
这不是很酷吗?
在你的 JavaScript 项目中使用 Tree-sitter
虽然 Tree-sitter 本身主要用 Rust 编写,但也有一些 JavaScript 绑定允许你通过 JavaScript 代码与其进行交互。以下是一些可以实现的功能:
- 安装:首先,您需要使用 npm 安装 Tree-sitter 库和 Python 解析器:
npm install tree-sitter tree-sitter-python --legacy-peer-deps
由于 peerDependencies 冲突,添加了 legacy-peer-deps 标志
-
编写一些 Python 代码:创建一个简单的 Python 文件,其中包含一些您想要分析的代码(例如
greet
之前的函数)。将此文件另存为your_code.py
。 -
导入库:在您的 JavaScript 文件中,导入必要的库:
const TreeSitter = require('tree-sitter');
const Python = require('tree-sitter-python');
const fs = require('fs').promises;
- 解析代码:使用库解析 Python 文件并生成 AST。操作方法如下:
async function parseCode(codePath) {
// Load the Python parser
const parser = new TreeSitter();
// Set the language to the parser
parser.setLanguage(Python);
// Read the code file content
const codeContent = await readFile(codePath, 'utf8');
// Parse the code using the chosen parser
const tree = await parser.parse(codeContent);
return tree.rootNode;
}
- 探索 AST(我们自己做!)
一开始这可能会让人不知所措,请坚持下去。
AST 是一个复杂的数据结构,但我们可以探索它的基本元素。以下是rootNode
对象的分解:
- rootNode.type:此属性告诉您节点的类型(例如,在我们的示例中为“function_definition”)。
- rootNode.children:这是一个包含当前节点子节点的数组。
- rootNode.text:此属性可能包含节点的实际文本内容(例如,函数名称或要打印的字符串)。
以下是一些探索 AST 根节点的示例代码:
async function printASTNodeInfo(rootNode) {
console.log(`Node type: ${rootNode.type}`);
// Loop through child nodes
for (const child of rootNode.children) {
console.log(` - Child node type: ${child.type}`);
// Explore child nodes recursively
if (child.children.length > 0) {
await printASTNodeInfo(child);
} else {
// For leaf nodes (no children), print the text content
if (child.text) {
console.log(` - Text content: ${child.text}`);
}
}
}
}
- 添加主要功能:将所有功能整合在一起
async function main(codePath) {
try {
const rootNode = await parseCode(codePath);
await printASTNodeInfo(rootNode);
} catch (error) {
console.error(`Failed to parse code: ${error.message}`);
}}
// Calling the main function
main(YOUR_CODE_PATH);
解释:
-
递归探索:代码现在包含一个
printASTNodeInfo
针对每个子节点的嵌套函数调用。这会创建一个递归循环,用于探索子节点的类型,然后进一步探索其子节点(如果有)。这允许您遍历整个 AST 结构。 -
叶节点:代码会检查是否存在子节点。如果某个子节点本身没有任何子节点(即它是叶节点),则它可能包含其所代表的代码元素的实际文本内容。代码会检查该
text
属性,并在可用时将其打印出来。
运行代码:
- 确保您已安装 Node.js 和 npm。
- 创建两个文件:(
your_code.py
包含您的 Python 代码)和analyze_code.js
(包含具有上述函数的 JavaScript 代码)。 - 在中
analyze_code.js
,修改parseCode
函数以返回整个 AST(tree
)而不是仅仅返回根节点。 - 在脚本中调用该
parseCode
函数,并将路径传递到 Python 文件,就像node analyze_code.js
在终端中一样。 - 一旦有了 AST(
tree
),就可以printASTNodeInfo
使用tree.rootNode
作为参数进行调用。
示例输出:
假设您的 Python 代码是greet
函数示例,则输出可能如下所示:
Node type: function_definition
- Child node type: identifier
- Text content: greet
- Child node type: parameter
- Text content: name
- Child node type: block_statement
- Child node type: expression_statement
- Child node type: call_expression
- Text content: print
- Child node type: string_literal
- Text content: Hello, + name + !Node type: module
- Child node type: function_definition
Node type: function_definition
- Child node type: def
- Text content: def
- Child node type: identifier
- Text content: greet
- Child node type: parameters
Node type: parameters
- Child node type: (
- Text content: (
- Child node type: identifier
- Text content: name
- Child node type: )
- Text content: )
....
这可以让你大致了解 AST 的结构,展示不同的节点类型,以及叶节点可能包含的一些文本内容。请记住,这只是一个基础的探索,根据你分析的代码,AST 可能会变得更加复杂。
观察树上保姆的行动(游乐场版)
- 访问 Tree-sitter 游乐场(https://tree-sitter.github.io/tree-sitter/playground)。
- 从语言下拉菜单中选择“Python”。
- 将您的 Python 代码片段(如
greet
函数)粘贴到代码编辑器中。 - 单击“解析”按钮。
太棒了!如果你的代码有效,你会在代码编辑器下方看到生成的 AST。你可以点击树中的不同节点来查看特定代码部分的更多信息。
超越基础知识:
虽然探索原始 AST 结构可以提供丰富的信息,但一些库提供了将 AST 可视化为树形结构的功能。这些库需要单独安装,可能需要额外的配置。然而,核心概念保持不变:使用 Tree-sitter 生成 AST,然后利用其他工具进行可视化或进一步分析。
GitGraph是我最近主要借助 tree-sitter 构建的项目之一。它可以将您的代码库(目前仅支持 Python 代码库)转换为交互式图表,展现函数、类和文件之间的关系。您可以通过拖动、缩放和悬停来深入探索,侧边栏会显示相邻节点和导入的函数。超链接可直接带您到源代码。使用 GitGraph 清晰简洁的依赖关系视图,您可以轻松掌握 Python 项目的结构。您可以在此处
查看后端源代码。 如果您喜欢,请点个⭐!
我们对 JavaScript 中 Tree-sitter 的探索到此结束。记住,这仅仅是个开始!随着你深入 Python 开发,Tree-sitter 可以成为理解复杂代码结构、提升编程效率的宝贵工具。
项目构想
您可以尝试以下项目想法:
- 为 GitGraph 添加更多语言支持。
- 一个浏览器扩展,使用 Tree-sitter 总结 GitHub 上的代码文件,快速洞察代码的结构和复杂性。
- 代码复杂度分析器可评估代码库中函数和方法的复杂性,并根据 AST 提供简化或重构的建议。
深入了解并在Twitter、GitHub和LinkedIn上关注我!
文章来源:https://dev.to/shreshthgoyal/understanding-code-struct-a-beginners-guide-to-tree-sitter-3bbc如果您觉得本指南有用,并创建了您自己的出色 CLI 工具,我非常乐意看到!请在下方评论区分享您的 GitHub 代码库。让我们一起创造奇迹!