go语言ast语法解析

通过Demo来了解语法解析的过程

了解 ast 语法解析,我们先从一个简单的 demo 开始,正向看看 ast 解析代码的过程,过程虽然不复杂,但是特别繁琐。

看下面的代码,真实的环境中 32 行的 ParsePeople 是不存在的,我们要使用 ast 语法解析,通过分析 14 行的 BuildPeople 来自动生成 33 行的 BuildPeople 代码。

业务上因为之前的写法有点难看了,但这种写法的代码又特别多,想结合 ast 来自动实现替换,这样也不太容易出错(整个例子都是假设的)。

在这里插入图片描述

核心的步骤就是①遍历整个语法树,找到目标的位置进行处理。这个例子比较简单,IfStmt 就是我们的目标位置,fSet和fNode、以及Inspect都属于标准处理方式。

接下来解析的就是②断言类型,你会遇到各种各样的语法类型,只需要不停地做断言,不停地做case判断。IfStmt 结构体中的两个成员,一个是 Cond 属于 Expr 接口类型,一个是 Body 属于 BlockStmt 类型。

import (
	"go/ast"
	"go/parser"
	"go/token"
	"log"
)

func main() {
	fSet := token.NewFileSet()
	fNode, err := parser.ParseFile(fSet, "/pwd/ifstat.txt", nil, parser.ParseComments)
	if err != nil {
		log.Fatal(err)
	}

	ast.Inspect(fNode, func(node ast.Node) bool {
		switch n := node.(type) {
		case *ast.IfStmt:
		}
		return true
	})
}

拿 Expr 这个接口来说,断言的时候,你完全不需要知道有哪些类型实现了这个接口,我们只需要勤劳一些,不停地做试探就可以了,我来举个例子,我们断言 Cond,只写一个 default 分支,然后打印 Cond 的类型信息

在这里插入图片描述
结合解析的代码可以知道,len(param) >= 2 在语法解析中的类型为 *ast.BinaryExpr,我们继续重复这样的操作就可以了。

这个例子我们不需要解析 Cond部分,因为我们完全可以通过解析 Body 的部分来构造我们想要的代码,将 Cond 的断言更换成对 Body 的断言。结合代码输出,我们可以知道,接下来要处理的类型是 赋值语句 *ast.AssignStmt

在这里插入图片描述
我们获取到AssignStmt结构体之后,紧接着就获取它左边的表达式和右边的表达式,继续断言
在这里插入图片描述
写到这里,这种不断试探断言的方式大家应该基本了解了,后面的方式处理方式也是相同的,下面是完整的处理逻辑。
在这里插入图片描述
我们通过已知的结果去生成另外一种结构,通过 ast 的方式写起来真的是非常繁琐,如果只靠纯文本的方式解析,也面临很多特殊的情况。

如果我们将这两种方式结合起来,势必会有事半功倍的效果。

将表达式转换为字符串

如果我们获取到表达式,我们可以直接将其转换为原始的字符串,通过字符串的方式去解析。我们一步一步入手

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值