3B.5 Unit Test及AST可视化
在了解了语法树的数据结构与基本解析思路之后,就没有必要继续钻入各个代码角落去学习解析细节了。此时更好的方式是反向学习:通过 UT 来调用解析函数,查看各种代码块的解析结果。
语法分析器很容易进行单元测试,因为其本质上只需要一段代码作为输入,对运行环境没有额外的要求,因此我们不需要做太多的初始化工作。测试文件 parsertest.go 中已经包含了很多测试用例可供参考,可以直接运行。但在运行 UT 或者构建自己的 UT 之前,我们先来看一下如何更好的查看语法树的内容,毕竟其内嵌结构可能很深。
文件 dumper.go 中的函数 Fdump 可以将一个 Node 的结构 dump 出来,而包括 File 在内,所有前面介绍过得结构体都实现了 Node 接口,所以该函数是我们可视化语法树的好工具。
下面我们通过一些 UT 来进一步学习一下语法解析的功能。
在 parser_test.go 内创建如下 UT
func TestParser(t *testing.T) {
code := `
package main
import (
"fmt"
"net/http"
)
const (a, b)
var names []string = make([]int, 10)
func iterate[T any](list []T, f func(T)) {
for _, t := range list {
f(t)
}
}
`
ast, _ := Parse(NewFileBase("dump_source.go"), bytes.NewBuffer([]byte(code)), func(err error) {
fmt.Printf("Parsing Error: %v\n", err)
}, nil, CheckBranches|AllowGenerics) // 开启泛型支持,以便解析出类型参数
if ast != nil {
Fdump(os.Stdout, ast)
}
}执行该 UT 得到输出结果:
但仔细查看我们所解析的代码,会发现其存在如下问题:
import 的库未使用
常量 a, b 没有初始化
变量 names 声明的类型与 make 中指定的类型不一致
iterate 声明中不需要返回值,但该函数却返回了一个字符串
但解析器依然成功完成了解析,这是因为此时解析器只是负责做语法分析,只要程序符合语言的文法规范,解析器就能够顺利完成;而上述问题是语义问题,或者是代码规范问题(import 的库未使用),不属于语法解析器的管理范围。想要处理这些问题,编译器还需要将语法树继续往后传递并进行进一步处理。
最后更新于
这有帮助吗?