树上看护新手指南

2025-06-07

树上看护新手指南

浏览大量或复杂的代码可能具有挑战性,但Tree-sitter可以提供帮助。

关键背景知识

树上看护者

Tree-sitter根据语言生成解析器,并提供引擎所见代码的洞察。它将杂乱的代码编织成一张清晰、结构化的图谱,揭示不同部分之间的关​​系。这张图谱被称为抽象语法树 (AST),它就像一个可视化的蓝图,使复杂的代码更易于理解。

抽象语法树(AST)

AST(抽象语法树)将代码分解为基本元素——变量、函数和表达式——并展示它们之间的相互作用,类似于家谱,每个人通过血缘关系相互联系。树的根代表整个程序,分支代表不同的部分。正如家谱阐明了关系一样,AST 使代码连接清晰可见。
更正式地说,它是源代码的图形表示,主要用于编译器读取代码并生成目标二进制文件。

您可以在这里使用您的代码,并将其可视化为 AST。

编码时间!

示例代码

让我们看看 AST 可视化和 Tree-sitter 如何为以下 Python 代码工作!



def greet(name):
  print("Hello, " + name + "!")


Enter fullscreen mode Exit fullscreen mode

在构建抽象语法树 (AST) 时,函数定义被指定为根节点,“greet” 和 “name” 构成其直系后代或子节点,以此来表明函数及其组件之间的层级关系。随后,print 语句作为函数定义的另一个子节点被集成到 AST 中,其内部语法结构被进一步细分,以表示操作及其操作数,如下图所示:

AST 可视化

上面形成的 AST 可以可视化为如下树:

AST 树

这不是很酷吗?

在你的 JavaScript 项目中使用 Tree-sitter

虽然 Tree-sitter 本身主要用 Rust 编写,但也有一些 JavaScript 绑定允许你通过 JavaScript 代码与其进行交互。以下是一些可以实现的功能:

  1. 安装:首先,您需要使用 npm 安装 Tree-sitter 库和 Python 解析器:


npm install tree-sitter tree-sitter-python --legacy-peer-deps


Enter fullscreen mode Exit fullscreen mode

由于 peerDependencies 冲突,添加了 legacy-peer-deps 标志

  1. 编写一些 Python 代码:创建一个简单的 Python 文件,其中包含一些您想要分析的代码(例如greet之前的函数)。将此文件另存为your_code.py

  2. 导入库:在您的 JavaScript 文件中,导入必要的库:



const TreeSitter = require('tree-sitter');
const Python = require('tree-sitter-python');
const  fs  =  require('fs').promises;


Enter fullscreen mode Exit fullscreen mode
  1. 解析代码:使用库解析 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;
}


Enter fullscreen mode Exit fullscreen mode
  1. 探索 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}`);
      }
    }
  }
}


Enter fullscreen mode Exit fullscreen mode
  1. 添加主要功能:将所有功能整合在一起


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);


Enter fullscreen mode Exit fullscreen mode

解释:

  1. 递归探索:代码现在包含一个printASTNodeInfo针对每个子节点的嵌套函数调用。这会创建一个递归循环,用于探索子节点的类型,然后进一步探索其子节点(如果有)。这允许您遍历整个 AST 结构。

  2. 叶节点:代码会检查是否存在子节点。如果某个子节点本身没有任何子节点(即它是叶节点),则它可能包含其所代表的代码元素的实际文本内容。代码会检查该text属性,并在可用时将其打印出来。

运行代码:

  1. 确保您已安装 Node.js 和 npm。
  2. 创建两个文件:(your_code.py包含您的 Python 代码)和analyze_code.js(包含具有上述函数的 JavaScript 代码)。
  3. 在中analyze_code.js,修改parseCode函数以返回整个 AST(tree)而不是仅仅返回根节点。
  4. 在脚本中调用该parseCode函数,并将路径传递到 Python 文件,就像node analyze_code.js在终端中一样。
  5. 一旦有了 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: )
....


Enter fullscreen mode Exit fullscreen mode

这可以让你大致了解 AST 的结构,展示不同的节点类型,以及叶节点可能包含的一些文本内容。请记住,这只是一个基础的探索,根据你分析的代码,AST 可能会变得更加复杂。

观察树上保姆的行动(游乐场版)

虽然 Tree-sitter 本身需要一些编程知识,但有一些在线工具可以让你亲眼见证它的运作!以下是使用https://tree-sitter.github.io/tree-sitter/playground的示例

  1. 访问 Tree-sitter 游乐场(https://tree-sitter.github.io/tree-sitter/playground)。
  2. 从语言下拉菜单中选择“Python”。
  3. 将您的 Python 代码片段(如greet函数)粘贴到代码编辑器中。
  4. 单击“解析”按钮。

太棒了!如果你的代码有效,你会在代码编辑器下方看到生成的 AST。你可以点击树中的不同节点来查看特定代码部分的更多信息。

超越基础知识:

虽然探索原始 AST 结构可以提供丰富的信息,但一些库提供了将 AST 可视化为树形结构的功能。这些库需要单独安装,可能需要额外的配置。然而,核心概念保持不变:使用 Tree-sitter 生成 AST,然后利用其他工具进行可视化或进一步分析。

GitGraph是我最近主要借助 tree-sitter 构建的项目之一。它可以将您的代码库(目前仅支持 Python 代码库)转换为交互式图表,展现函数、类和文件之间的关系。您可以通过拖动、缩放和悬停来深入探索,侧边栏会显示相邻节点和导入的函数。超链接可直接带您到源代码。使用 GitGraph 清晰简洁的依赖关系视图,您可以轻松掌握 Python 项目的结构。您可以在此处
查看后端源代码 如果您喜欢,请点个⭐!

我们对 JavaScript 中 Tree-sitter 的探索到此结束。记住,这仅仅是个开始!随着你深入 Python 开发,Tree-sitter 可以成为理解复杂代码结构、提升编程效率的宝贵工具。

项目构想

您可以尝试以下项目想法:

  • 为 GitGraph 添加更多语言支持。
  • 一个浏览器扩展,使用 Tree-sitter 总结 GitHub 上的代码文件,快速洞察代码的结构和复杂性。
  • 代码复杂度分析器可评估代码库中函数和方法的复杂性,并根据 AST 提供简化或重构的建议。

深入了解并在TwitterGitHubLinkedIn上关注我!

如果您觉得本指南有用,并创建了您自己的出色 CLI 工具,我非常乐意看到!请在下方评论区分享您的 GitHub 代码库。让我们一起创造奇迹!

文章来源:https://dev.to/shreshthgoyal/understanding-code-struct-a-beginners-guide-to-tree-sitter-3bbc
PREV
使用 PostgreSQL 在 NodeJS 中进行用户授权
NEXT
面向对象编程概念(OOP)简化!!!