- 人工智能
- AI 技能
- 文档
- 开发工具
【免费下载链接】DocAgent
导读
StructDecl是仓颉标准库std.ast中表示Struct(结构体)声明节点的核心 AST 类,用于在宏展开、源码分析与代码生成场景下描述"结构体定义"这一语法结构。本篇基于 StructDecl_class.md 展开,完整讲解StructDecl的构造函数、四个成员属性(body、superTypes、superTypeBitAnds、upperBound)的语义与约束,并结合std.ast的解析函数与操作样本,给出从仓颉源码到StructDecl节点、再到节点读写与遍历的完整实战方案。
StructDecl 在语法树中的定位
继承关系与声明族谱
在 ast_package_classes.md 中,StructDecl的类声明为:
public class StructDecl <: Decl { public init() public init(inputs: Tokens) }StructDecl直接继承自 Decl。Decl是所有声明节点的父类(类定义ClassDecl、接口定义InterfaceDecl、函数定义FuncDecl、枚举定义EnumDecl、扩展定义ExtendDecl等均属Decl),而Decl又继承自 Node。因此StructDecl天然具备Node提供的通用能力:
dump():将节点以树形结构打印;toTokens():将语法树节点还原为Tokens词法单元序列;traverse(v: Visitor):遍历当前节点及其子节点;beginPos/endPos:节点的起始与终止位置信息。
同时StructDecl也继承了Decl的通用属性,例如identifier(声明名)、keyword(关键字)、modifiers(修饰符列表)、annotations(注解列表)、genericParam(类型形参列表)、genericConstraint(泛型约束)、isGenericDecl(是否泛型节点)等。
Struct 定义的语法骨架
按照 ast_package_classes.md 的描述,Struct 的定义使用struct关键字,定义依次为:
可缺省的修饰符 →
struct关键字 → struct 名 → 可选的类型参数 → 是否指定父接口 → 可选的泛型约束 → struct 体的定义
一个典型的StructDecl对应的源码形态(本示例基于上述语法骨架构造,便于对照后续属性讲解):
struct Point { var x: Int64 var y: Int64 }带父接口(<:与&)的形态:
struct Point <: Comparable<Point> & Hashable { var x: Int64 var y: Int64 }其中<:用于声明父接口关系,&用于连接多个父接口,这两者正是StructDecl专属属性所对应的语法元素。
构造函数:如何创建 StructDecl 节点
StructDecl提供两个构造函数,均来自关联文档的构造函数表:
| 名称 | 原型 | 说明 |
|---|---|---|
| init | () | 构造一个默认的 StructDecl 对象。 |
| init | (inputs: Tokens) | 构造一个 StructDecl 对象。 |
init():默认对象
public init()构造一个内容为空、各属性处于初始状态的StructDecl对象。通常用于需要"从零组装"一个结构体声明节点的场景,例如在宏代码生成中手动拼接声明。
init(Tokens):从词法单元构造
public init(inputs: Tokens)接收一组词法单元Tokens,将其解析并构造成StructDecl节点。这里有几个使用要点:
Tokens的来源:既可以通过 cangjieLex 将字符串词法化得到,也可以直接使用quote(...)表达式生成。例如:
import std.ast.* main() { let input: Tokens = quote( struct Point { var x: Int64 var y: Int64 } ) let decl = StructDecl(input) // 从词法单元直接构造 StructDecl 节点 println(decl.toTokens()) }- 异常行为:当传入的
Tokens无法构造为StructDecl节点时,会抛出 ASTException(见 ast_package_classes.md 中init(Tokens)的异常说明)。例如传入一段func函数声明或class类声明的词法单元,类型不匹配时即会触发异常。
成员属性详解:StructDecl 的四个专属属性
关联文档列出StructDecl的四个成员属性,它们是读写结构体声明信息的主要入口:
| 名称 | 原型 | 说明 |
|---|---|---|
| body | public mut prop body: Body | 获取或设置 StructDecl 节点的类体。 |
| superTypeBitAnds | public mut prop superTypeBitAnds: Tokens | 获取或设置父接口声明中的&操作符的词法单元序列,可能为空。 |
| superTypes | public mut prop superTypes: ArrayList<TypeNode> | 获取或设置 StructDecl 节点的父接口。 |
| upperBound | public mut prop upperBound: Token | 获取或设置<:操作符。 |
body:结构体体
- 类型:Body
- 语义:获取或设置
StructDecl节点的"类体",即由{}及内部声明节点组成的结构。
Body本身承载了三个成员:
decls: ArrayList<Decl>:体内部的声明节点集合(成员变量、构造函数、成员函数等);lBrace: Token:左花括号{;rBrace: Token:右花括号}。
对结构体成员做增删改查,本质上就是对body.decls这个ArrayList<Decl>的操作。例如向结构体追加一个成员函数:
var structDecl = ... // 已获取的 StructDecl 节点 var funcDecl = FuncDecl(quote(func distance(): Int64 { 0 })) structDecl.body.decls.add(funcDecl) // 向结构体体追加一个成员函数声明这与 operate.md 中对ClassDecl.body.decls的增删改查模式完全一致(ClassDecl与StructDecl共享body: Body结构)。
superTypes:父接口集合
- 类型:ArrayList<TypeNode>
- 语义:获取或设置
StructDecl节点的父接口。TypeNode是所有类型节点的父类,结构体声明中struct Point <: Comparable<Point> & Hashable的Comparable<Point>、Hashable即会解析为superTypes中的TypeNode元素。
superTypeBitAnds:父接口间的&操作符
- 类型:Tokens
- 语义:获取或设置父接口声明中的
&操作符的词法单元序列;当只有一个父接口(无&连接)时该序列为空。
Tokens是Token序列的封装类型,支持size、get(index)、append、remove、toBytes、toString等操作。注意该属性的设置约束(见 ast_package_classes.md):当设置的Tokens不是&词法单元序列时,抛出 ASTException。
upperBound:<:操作符
- 类型:Token
- 语义:获取或设置
<:操作符。Token是词法单元类型,包含kind(词法单元类型)、value(字面量值)、pos(位置信息)等字段。
同样地,该属性也有设置约束:当设置的Token不是<:操作符时,抛出 ASTException。
从源码到 StructDecl:解析链路的完整用法
实际开发中,StructDecl节点通常不是手工init构造的,而是通过std.ast提供的解析函数从仓颉源码获取。推荐链路如下:
- 词法化:使用 cangjieLex(
public func cangjieLex(code: String): Tokens)将源码字符串转为Tokens,或直接用quote(...)内联生成; - 解析声明:调用 parseDecl(
public func parseDecl(input: Tokens, astKind!: String = ""): Decl)得到一个Decl节点; - 类型转换:通过
as StructDecl结合match将其收敛为StructDecl。
完整示例(参考 parse.md 与 operate.md 的写法):
import std.ast.* main() { let input: Tokens = quote( struct Point <: Comparable<Point> & Hashable { var x: Int64 var y: Int64 init(x_: Int64, y_: Int64) { x = x_ y = y_ } } ) let decl = parseDecl(input) // 获取一个 Decl 声明节点 var structDecl = match (decl as StructDecl) { // 类型转换为 StructDecl case Some(v) => v case None => throw Exception() } println("Identifier value is ${structDecl.identifier.value}") println("SuperTypes size is ${structDecl.superTypes.size}") println("Body size is ${structDecl.body.decls.size}") structDecl.dump() // 打印整棵语法树结构 0 }关于parseDecl的两个补充说明(见 ast_package_funcs.md):
- 该函数不支持解析
FuncParam类型; - 可选参数
astKind!支持PrimaryCtorDecl与PropMemberDecl两个取值,分别用于解析主构造函数与prop的 getter/setter,与结构体声明解析本身无冲突。
实战:操作 StructDecl 节点的常用手法
读取与校验结构体信息
结构体声明分析通常需要读取名称、父接口与成员。利用继承自Decl的属性与StructDecl自身属性即可完成:
// structDecl 为已获取的 StructDecl 节点 let name: Token = structDecl.identifier // 结构体名,如 Point let ifaces = structDecl.superTypes // 父接口 TypeNode 列表 let bitAnds = structDecl.superTypeBitAnds // 父接口间的 & 序列(可能为空) let upper = structDecl.upperBound // <: 操作符 let members = structDecl.body.decls // 结构体体内声明集合若父接口为空(未声明父接口的普通结构体),superTypeBitAnds与upperBound对应的语法元素自然缺失,读取时按空处理即可。
打印与还原
- 节点级
dump():将StructDecl及其子树以树形结构打印,便于调试排查,参见 dump.md 中dump函数的用法; - 节点级
toTokens():将StructDecl还原为Tokens词法单元,可用于宏展开中把修改后的声明重新输出为源码。
遍历子节点
借助 Node.traverse 与 Visitor,可以递归访问StructDecl内嵌套的变量声明、函数声明等子节点。参考 traverse.md 的写法——继承Visitor并重写对应visit函数(如visit(varDecl: VarDecl)),再对structDecl调用traverse(visitor)即可,配合breakTraverse()可控制遍历终止。
易错点与异常小结
StructDecl相关的异常行为集中在两处(均见 ast_package_classes.md):
- 构造异常:
init(Tokens)传入的词法单元无法构成StructDecl时抛出 ASTException; - 属性赋值异常:
superTypeBitAnds被设置为非&词法单元序列、或upperBound被设置为非<:操作符时,均抛出ASTException。
因此在对superTypeBitAnds与upperBound赋值前,务必确认词法单元种类与字面量值符合预期;而对body、superTypes的读写则相对宽松,可安全地替换整个Body或ArrayList<TypeNode>。
总结
StructDecl是std.ast声明节点族中面向结构体定义的专用节点:构造函数覆盖"空对象"与"词法单元构造"两种创建方式,body、superTypes、superTypeBitAnds、upperBound四个属性精确映射结构体声明语法骨架中的体、父接口、&连接符与<:操作符。配合quote/cangjieLex/parseDecl的解析链路,以及dump/toTokens/traverse的通用节点能力,开发者可以在宏编程、源码分析与代码生成场景中完整地读取、修改和重建结构体声明。更多上下文可继续阅读 ast_package_overview.md 与 readme.md 中的解析函数与节点全景。
- 人工智能
- AI 技能
- 文档
- 开发工具
【免费下载链接】DocAgent
相关推荐
仓颉 std.ast 语法树节点详解:VarDecl 变量定义节点的构造、属性访问与实战操作
仓颉 std.ast 语法树节点详解:VarDecl 变量定义节点的构造、属性访问与实战操作 本文以仓颉标准库 std.ast 包中的 VarDecl 类为核心
人工智能AI 技能文档开发工具仓颉 std.ast 语法树节点解析:ArrayLiteral 数组字面量节点的构造、属性与实战用法
仓颉 std.ast 语法树节点解析:ArrayLiteral 数组字面量节点的构造、属性与实战用法 ArrayLiteral 是仓颉标准库 std.ast 包
人工智能AI 技能文档开发工具仓颉 std.ast IfExpr 条件表达式节点详解:语法结构、构造方法与实战操作
仓颉 std.ast IfExpr 条件表达式节点详解:语法结构、构造方法与实战操作 本文深入解析仓颉标准库 std.ast 中用于表示条件表达式的 AST 节
人工智能AI 技能文档开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考