仓颉编程语言 std.ast 实战:自定义 Visitor 访问函数遍历 AST 节点 文档知识库教程OpenHarmony【免费下载链接】CangjieCorpus本仓库为仓颉编程语言语料库聚焦 仓颉编程语言 核心知识体系整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源经结构化处理与专业标注构建为支持 RAG检索增强生成技术 的高质量知识基座适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用推动鸿蒙开发生态智能化升级项目地址https://gitcode.com/Cangjie/CangjieCorpus点击查看免费下载导读本文围绕仓颉标准库std.ast提供的Visitor访问者机制展开以官方示例“自定义访问函数遍历 AST 对象”为骨架完整演示如何通过继承Visitor、重写visit函数并结合Node.traverse()实现语法树的深度遍历。读完本文你将掌握如何对仓颉源码解析出的抽象语法树AST进行按类型定向访问、如何在遍历中借助ASTException识别未初始化变量等语义特征以及如何使用breakTraverse()提前终止子树遍历为开发宏、代码分析工具或智能编码辅助能力打下基础。一、背景std.ast 包的解析与遍历能力仓颉std.ast包的核心职责是提供仓颉源码的语法解析器和语法树节点它可以把源码的词法单元Tokens解析为抽象语法树节点对象相关能力详见 ast 包总览。在 解析示例 中可以看到通过parseDecl等解析函数即可把一段class Data { ... }源码转换为ClassDecl节点再通过dump()打印出树形结构。而“遍历”则是解析之后的第二步关键操作。std.ast为所有语法树节点的公共父类 Node 提供了统一的遍历接口public func traverse(v: Visitor): Unit该函数用于遍历当前语法树节点及其子节点源码定义。traverse与Visitor搭配使用即可实现对节点的访问和修改。本文要讲解的示例正是这套机制的最小完整落地。二、核心示例遍历变量声明并收集未初始化变量示例的目标非常明确遍历 AST找到未定义变量即未初始化的变量声明VarDecl将其变量标识符词法单元收集起来。完整代码如下来源traverse.mdimport std.ast.* class MyVisitor : Visitor { public var uninitializedVars Tokens() // 存储变量词法单元 override public func visit(varDecl: VarDecl) { try { varDecl.expr } catch (e: ASTException) { uninitializedVars.append(varDecl.identifier) } breakTraverse() // 不会继续遍历 varDecl 的子节点 return } } main(): Int64 { let input quote( var a : Int64 ) let varDecl parseDecl(input) let visitor MyVisitor() // MyVisitor中定义了对 varDecl 节点的处理 varDecl.traverse(visitor) // 实现对 varDecl 节点的处理 println(Uninitialized VarDecl size is ${visitor.uninitializedVars.size}) 0 }运行结果Uninitialized VarDecl size is 1这段程序只用了十几行代码就把解析源码 → 构造访问者 → 遍历节点 → 收集结果的完整链路串了起来下面逐段拆解。三、逐层拆解从 quote 到 traverse 的完整调用链3.1 用 quote 构造词法单元输入let input quote(var a : Int64)中的quote是宏/ast 场景下的引用表达式它会将括号内的仓颉源码片段转换为 Tokens 类型的词法单元序列对应的语法树节点类型为 QuoteExpr。Tokens是对 Token 序列的封装类型提供size、append等操作而Token则携带kind词法种类如IDENTIFIER、VAR、pos源码位置和value字面量值三个核心字段Token 结构体定义。3.2 用 parseDecl 得到 VarDecl 节点parseDecl(input)是 解析函数 的声明级入口它把一组词法单元解析为一个 Decl 类型节点。因为输入恰好是一句var a : Int64变量声明所以解析结果实际是 VarDecl 节点——它是Decl的子类表示变量定义节点如var a: String、var b: Int64 1。说明parseDecl还支持可选的astKind!参数如PrimaryCtorDecl、PropMemberDecl用于指定解析特定节点类型当输入的词法单元无法构造为Decl节点时会抛出 ParseASTException。3.3 继承 Visitor 并重写 visit 函数Visitor 是一个public abstract class其内部默认定义了访问不同类型 AST 节点的visit函数所有visit函数都有默认为空的实现可以按需只实现自己关心的类型该类需要被继承使用并允许子类重新定义访问函数。示例中class MyVisitor : Visitor只重写了visit(varDecl: VarDecl)其他节点类型的访问行为保持默认空实现即什么都不做。这正是访问者模式在 AST 遍历中的典型用法按节点类型分发定向处理。varDecl.expr是 VarDecl 的属性用于获取或设置变量的初始化节点。从 API 文档 可以看到当VarDecl节点没有对变量进行初始化时访问expr属性会抛出 ASTException。于是try { varDecl.expr } catch (e: ASTException) { uninitializedVars.append(varDecl.identifier) }就构成了一个初始化检测var a : Int64没有初始值读取expr抛异常进入catch分支把变量名a对应的标识符TokenvarDecl.identifier继承自 Decl追加进uninitializedVars。uninitializedVars的类型是Tokens()append(varDecl.identifier)调用的是 Tokens.append(Token) 拼接接口。3.4 breakTraverse提前终止子节点遍历breakTraverse()是 Visitor 的内置方法用于在重写的visit函数中调用以终止继续遍历子节点的行为。对于var a : Int64这样的简单声明其子节点包含pattern、declType等示例在检测完初始化情况后立刻调用breakTraverse()表示本节点处理完毕无需再深入其子节点避免了对类型节点Int64等无关子结构的无谓访问。这既是性能优化也保证了访问逻辑的聚焦。3.5 traverse 驱动整个流程最后一行varDecl.traverse(visitor)是关键动作varDecl是 Node 的子类调用 Node.traverse(Visitor)traverse会遍历当前语法树节点及其所有子节点对每个节点按类型分发调用visitor中对应的visit函数在本例中根节点就是VarDecl因此MyVisitor.visit(varDecl: VarDecl)被触发一次uninitializedVars收集到 1 个词法单元。最终visitor.uninitializedVars.size为 1与运行结果一致。四、关键 API 速查为了让读者在实际开发中能直接对照使用将示例涉及的 API 汇总如下API签名/类型作用Visitorpublic abstract class Visitor抽象访问者类内部默认定义了各类 AST 节点的visit函数默认空实现Visitor.breakTraverse()public func breakTraverse(): Unit在visit函数中调用终止继续遍历当前节点的子节点Node.traverse(Visitor)public func traverse(v: Visitor): Unit遍历当前节点及其子节点参数为Visitor实例VarDeclpublic class VarDecl : Decl变量定义节点如var a: String、var b: Int64 1VarDecl.exprpublic mut prop expr: Expr变量初始化节点未初始化时访问抛出ASTExceptionVarDecl.identifierpublic mut open prop identifier: Token定义节点标识符继承自Decl如var a中的aTokenspublic open class Tokens对Token序列的封装提供size、append(Token)等Tokenpublic struct Token词法单元含kind、pos、value、delimiterNumASTExceptionpublic class ASTException : Exceptionast 库异常类在 ast 库调用过程中发生异常时使用parseDecl(Tokens)public func parseDecl(input: Tokens, astKind!: String ): Decl将词法单元解析为Decl类型节点五、扩展实践把遍历能力用于真实场景5.1 同时处理多种节点类型Visitor的visit函数可以按需重写任意多个。例如在同一个访问者中同时处理VarDecl和 FuncDecl即可在一次遍历中同时收集未初始化变量与函数定义信息。由于traverse会深度遍历整棵子树所有嵌套声明都会被依次分发无需手工递归。5.2 只遍历、不深入breakTraverse 的取舍当某个节点自身已包含全部所需信息时调用breakTraverse()可避免继续下钻。反之如果分析目标位于深层例如需要检查VarDecl初始化表达式内部的函数调用则不应调用breakTraverse()让traverse继续向下分发。5.3 遍历与修改结合Visitor的visit函数不仅可读也可改结合 操作 AST 对象示例 中直接对节点属性如classDecl.body.decls.add(...)进行增删改的手法可以在遍历过程中按需改写语法树节点这正是实现宏代码生成与代码变换的基础能力。5.4 与 dump 配合调试如果希望观察遍历前的树结构可在解析后调用 Node.dump()它会以树形格式打印当前节点及其属性语法树节点打印示例。将dump()与自定义visit结合可以快速定位哪个节点被访问、哪个子节点被跳过。六、小结通过本文的示例可以看到仓颉std.ast的Visitor traverse机制提供了一种声明式、类型分发的 AST 遍历方式继承 Visitor 定义看到某类节点做什么调用 Node.traverse(Visitor) 完成整棵树的驱动再配合breakTraverse()精确控制遍历深度、ASTException识别节点语义特征。这套模式可用于未初始化变量检查、代码风格扫描、宏展开辅助、智能编码提示等各类面向仓颉源码的分析与生成场景是深入理解仓颉语法树编程的重要一步。赞分享文档知识库教程OpenHarmony【免费下载链接】CangjieCorpus本仓库为仓颉编程语言语料库聚焦 仓颉编程语言 核心知识体系整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源经结构化处理与专业标注构建为支持 RAG检索增强生成技术 的高质量知识基座适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用推动鸿蒙开发生态智能化升级项目地址https://gitcode.com/Cangjie/CangjieCorpus点击查看免费下载相关推荐仓颉 std.ast 包 AST 节点类体系全解析节点类型、构造方式与遍历机制仓颉 std.ast 包 AST 节点类体系全解析节点类型、构造方式与遍历机制 导读 std.ast 是仓颉标准库中面向编译器前端与宏系统的核心包它提供仓颉编程语言语言运行时标准库垃圾回收并发编程仓颉语言 std.ast 包 AST 节点类全解析语法树类型体系与宏编程实践指南仓颉语言 std.ast 包 AST 节点类全解析语法树类型体系与宏编程实践指南 导读 仓颉编程语言的标准库 std.ast 包提供了源码语法解析器与完整的文档知识库教程OpenHarmony仓颉 std.ast 实参节点 Argument 详解函数调用参数在 AST 中的表示与操作仓颉 std.ast 实参节点 Argument 详解函数调用参数在 AST 中的表示与操作 Argument 是仓颉标准库 std.ast 包中用于表示 函人工智能AI 技能文档开发工具上一篇brpc /status 服务监控页详解字段含义、数据来源与 Describable 自定义状态输出下一篇res-downloader 教程十分钟把视频号、抖音的视频存到本地创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考