golang AST语法树解析

1. 源码示例

package mainimport ("context"
)// Foo 结构体
type Foo struct {i int
}// Bar 接口
type Bar interface {Do(ctx context.Context) error
}// main方法
func main() {a := 1
}

2. Golang中的AST

golang官方提供的几个包,可以帮助我们进行AST分析:

  • go/scanner:词法解析,将源代码分割成一个个token

  • go/token:token类型及相关结构体定义

  • go/ast:ast的结构定义

    • ast的各种结构定义入口在go/ast/ast.go
  • go/parser:语法分析,读取token流生成ast

通过上述的四个库,我们就可以实现golang代码的语法树分析

3. 使用main.go解析demo.go的AST树

package mainimport ("go/ast""go/parser""go/token""log""path/filepath"
)func main() {fset := token.NewFileSet()// 这里取绝对路径,方便打印出来的语法树可以转跳到编辑器path, _ := filepath.Abs("./demo.go")f, err := parser.ParseFile(fset, path, nil, parser.AllErrors)if err != nil {log.Println(err)return}// 打印语法树ast.Print(fset, f)
}

3.1. 解析的结果如下

可在http://goast.yuroyoro.net/里贴上源代码后查看

*ast.File {1  .  Package: 1:12  .  Name: *ast.Ident {3  .  .  NamePos: 1:94  .  .  Name: "main"5  .  }6  .  Decls: []ast.Decl (len = 4) {7  .  .  0: *ast.GenDecl {8  .  .  .  TokPos: 3:19  .  .  .  Tok: import10  .  .  .  Lparen: 3:811  .  .  .  Specs: []ast.Spec (len = 1) {12  .  .  .  .  0: *ast.ImportSpec {13  .  .  .  .  .  Path: *ast.BasicLit {14  .  .  .  .  .  .  ValuePos: 4:215  .  .  .  .  .  .  Kind: STRING16  .  .  .  .  .  .  Value: "\"context\""17  .  .  .  .  .  }18  .  .  .  .  .  EndPos: -19  .  .  .  .  }20  .  .  .  }21  .  .  .  Rparen: 5:122  .  .  }23  .  .  1: *ast.GenDecl {24  .  .  .  TokPos: 8:125  .  .  .  Tok: type26  .  .  .  Lparen: -27  .  .  .  Specs: []ast.Spec (len = 1) {28  .  .  .  .  0: *ast.TypeSpec {29  .  .  .  .  .  Name: *ast.Ident {30  .  .  .  .  .  .  NamePos: 8:631  .  .  .  .  .  .  Name: "Foo"32  .  .  .  .  .  .  Obj: *ast.Object {33  .  .  .  .  .  .  .  Kind: type34  .  .  .  .  .  .  .  Name: "Foo"35  .  .  .  .  .  .  .  Decl: *(obj @ 28)36  .  .  .  .  .  .  }37  .  .  .  .  .  }38  .  .  .  .  .  Type: *ast.StructType {39  .  .  .  .  .  .  Struct: 8:1040  .  .  .  .  .  .  Fields: *ast.FieldList {41  .  .  .  .  .  .  .  Opening: 8:1742  .  .  .  .  .  .  .  List: []*ast.Field (len = 1) {43  .  .  .  .  .  .  .  .  0: *ast.Field {44  .  .  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {45  .  .  .  .  .  .  .  .  .  .  0: *ast.Ident {46  .  .  .  .  .  .  .  .  .  .  .  NamePos: 9:247  .  .  .  .  .  .  .  .  .  .  .  Name: "i"48  .  .  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {49  .  .  .  .  .  .  .  .  .  .  .  .  Kind: var50  .  .  .  .  .  .  .  .  .  .  .  .  Name: "i"51  .  .  .  .  .  .  .  .  .  .  .  .  Decl: *(obj @ 43)52  .  .  .  .  .  .  .  .  .  .  .  }53  .  .  .  .  .  .  .  .  .  .  }54  .  .  .  .  .  .  .  .  .  }55  .  .  .  .  .  .  .  .  .  Type: *ast.Ident {56  .  .  .  .  .  .  .  .  .  .  NamePos: 9:457  .  .  .  .  .  .  .  .  .  .  Name: "int"58  .  .  .  .  .  .  .  .  .  }59  .  .  .  .  .  .  .  .  }60  .  .  .  .  .  .  .  }61  .  .  .  .  .  .  .  Closing: 10:162  .  .  .  .  .  .  }63  .  .  .  .  .  .  Incomplete: false64  .  .  .  .  .  }65  .  .  .  .  }66  .  .  .  }67  .  .  .  Rparen: -68  .  .  }69  .  .  2: *ast.GenDecl {70  .  .  .  TokPos: 13:171  .  .  .  Tok: type72  .  .  .  Lparen: -73  .  .  .  Specs: []ast.Spec (len = 1) {74  .  .  .  .  0: *ast.TypeSpec {75  .  .  .  .  .  Name: *ast.Ident {76  .  .  .  .  .  .  NamePos: 13:677  .  .  .  .  .  .  Name: "Bar"78  .  .  .  .  .  .  Obj: *ast.Object {79  .  .  .  .  .  .  .  Kind: type80  .  .  .  .  .  .  .  Name: "Bar"81  .  .  .  .  .  .  .  Decl: *(obj @ 74)82  .  .  .  .  .  .  }83  .  .  .  .  .  }84  .  .  .  .  .  Type: *ast.InterfaceType {85  .  .  .  .  .  .  Interface: 13:1086  .  .  .  .  .  .  Methods: *ast.FieldList {87  .  .  .  .  .  .  .  Opening: 13:2088  .  .  .  .  .  .  .  List: []*ast.Field (len = 1) {89  .  .  .  .  .  .  .  .  0: *ast.Field {90  .  .  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {91  .  .  .  .  .  .  .  .  .  .  0: *ast.Ident {92  .  .  .  .  .  .  .  .  .  .  .  NamePos: 14:293  .  .  .  .  .  .  .  .  .  .  .  Name: "Do"94  .  .  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {95  .  .  .  .  .  .  .  .  .  .  .  .  Kind: func96  .  .  .  .  .  .  .  .  .  .  .  .  Name: "Do"97  .  .  .  .  .  .  .  .  .  .  .  .  Decl: *(obj @ 89)98  .  .  .  .  .  .  .  .  .  .  .  }99  .  .  .  .  .  .  .  .  .  .  }100  .  .  .  .  .  .  .  .  .  }101  .  .  .  .  .  .  .  .  .  Type: *ast.FuncType {102  .  .  .  .  .  .  .  .  .  .  Func: -103  .  .  .  .  .  .  .  .  .  .  Params: *ast.FieldList {104  .  .  .  .  .  .  .  .  .  .  .  Opening: 14:4105  .  .  .  .  .  .  .  .  .  .  .  List: []*ast.Field (len = 1) {106  .  .  .  .  .  .  .  .  .  .  .  .  0: *ast.Field {107  .  .  .  .  .  .  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {108  .  .  .  .  .  .  .  .  .  .  .  .  .  .  0: *ast.Ident {109  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: 14:5110  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "ctx"111  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {112  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Kind: var113  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "ctx"114  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Decl: *(obj @ 106)115  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }116  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }117  .  .  .  .  .  .  .  .  .  .  .  .  .  }118  .  .  .  .  .  .  .  .  .  .  .  .  .  Type: *ast.SelectorExpr {119  .  .  .  .  .  .  .  .  .  .  .  .  .  .  X: *ast.Ident {120  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: 14:9121  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "context"122  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }123  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Sel: *ast.Ident {124  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: 14:17125  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "Context"126  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }127  .  .  .  .  .  .  .  .  .  .  .  .  .  }128  .  .  .  .  .  .  .  .  .  .  .  .  }129  .  .  .  .  .  .  .  .  .  .  .  }130  .  .  .  .  .  .  .  .  .  .  .  Closing: 14:24131  .  .  .  .  .  .  .  .  .  .  }132  .  .  .  .  .  .  .  .  .  .  Results: *ast.FieldList {133  .  .  .  .  .  .  .  .  .  .  .  Opening: -134  .  .  .  .  .  .  .  .  .  .  .  List: []*ast.Field (len = 1) {135  .  .  .  .  .  .  .  .  .  .  .  .  0: *ast.Field {136  .  .  .  .  .  .  .  .  .  .  .  .  .  Type: *ast.Ident {137  .  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: 14:26138  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "error"139  .  .  .  .  .  .  .  .  .  .  .  .  .  }140  .  .  .  .  .  .  .  .  .  .  .  .  }141  .  .  .  .  .  .  .  .  .  .  .  }142  .  .  .  .  .  .  .  .  .  .  .  Closing: -143  .  .  .  .  .  .  .  .  .  .  }144  .  .  .  .  .  .  .  .  .  }145  .  .  .  .  .  .  .  .  }146  .  .  .  .  .  .  .  }147  .  .  .  .  .  .  .  Closing: 15:1148  .  .  .  .  .  .  }149  .  .  .  .  .  .  Incomplete: false150  .  .  .  .  .  }151  .  .  .  .  }152  .  .  .  }153  .  .  .  Rparen: -154  .  .  }155  .  .  3: *ast.FuncDecl {156  .  .  .  Name: *ast.Ident {157  .  .  .  .  NamePos: 18:6158  .  .  .  .  Name: "main"159  .  .  .  .  Obj: *ast.Object {160  .  .  .  .  .  Kind: func161  .  .  .  .  .  Name: "main"162  .  .  .  .  .  Decl: *(obj @ 155)163  .  .  .  .  }164  .  .  .  }165  .  .  .  Type: *ast.FuncType {166  .  .  .  .  Func: 18:1167  .  .  .  .  Params: *ast.FieldList {168  .  .  .  .  .  Opening: 18:10169  .  .  .  .  .  Closing: 18:11170  .  .  .  .  }171  .  .  .  }172  .  .  .  Body: *ast.BlockStmt {173  .  .  .  .  Lbrace: 18:13174  .  .  .  .  List: []ast.Stmt (len = 1) {175  .  .  .  .  .  0: *ast.AssignStmt {176  .  .  .  .  .  .  Lhs: []ast.Expr (len = 1) {177  .  .  .  .  .  .  .  0: *ast.Ident {178  .  .  .  .  .  .  .  .  NamePos: 19:2179  .  .  .  .  .  .  .  .  Name: "a"180  .  .  .  .  .  .  .  .  Obj: *ast.Object {181  .  .  .  .  .  .  .  .  .  Kind: var182  .  .  .  .  .  .  .  .  .  Name: "a"183  .  .  .  .  .  .  .  .  .  Decl: *(obj @ 175)184  .  .  .  .  .  .  .  .  }185  .  .  .  .  .  .  .  }186  .  .  .  .  .  .  }187  .  .  .  .  .  .  TokPos: 19:4188  .  .  .  .  .  .  Tok: :=189  .  .  .  .  .  .  Rhs: []ast.Expr (len = 1) {190  .  .  .  .  .  .  .  0: *ast.BasicLit {191  .  .  .  .  .  .  .  .  ValuePos: 19:7192  .  .  .  .  .  .  .  .  Kind: INT193  .  .  .  .  .  .  .  .  Value: "1"194  .  .  .  .  .  .  .  }195  .  .  .  .  .  .  }196  .  .  .  .  .  }197  .  .  .  .  }198  .  .  .  .  Rbrace: 20:1199  .  .  .  }200  .  .  }201  .  }202  .  Scope: *ast.Scope {203  .  .  Objects: map[string]*ast.Object (len = 3) {204  .  .  .  "Foo": *(obj @ 32)205  .  .  .  "Bar": *(obj @ 78)206  .  .  .  "main": *(obj @ 159)207  .  .  }208  .  }209  .  Imports: []*ast.ImportSpec (len = 1) {210  .  .  0: *(obj @ 12)211  .  }212  .  Unresolved: []*ast.Ident (len = 3) {213  .  .  0: *(obj @ 55)214  .  .  1: *(obj @ 119)215  .  .  2: *(obj @ 136)216  .  }217  }

4. AST树结构

// 该结构体位于标准包 go/ast/ast.go 中,有兴趣可以转跳到源码阅读更详尽的注释
type File struct {Doc        *CommentGroup   // 如果文件有文档,则文档会被存储在这个结构体中,否则为 nilPackage    token.Pos       // "package"关键字,主要是所在的位置信息Name       *Ident          // package的名字Decls      []Decl          // 文件级别的声明。它包含文件中所有变量、函数、类型声明。如果文件中没有声明,则 decls 值为 nilScope      *Scope          // 包级作用域。它代表包级作用域,包含所有在包内声明的变量和函数。它对当前文件有效Imports    []*ImportSpec   // imports in this fileUnresolved []*Ident        // unresolved identifiers in this file。未使用的标识符Comments   []*CommentGroup // 文件中的所有注释。它包含文件中所有注释的列表
}

img

img

4.1. Doc

如果文件有文档,则文档会被存储在这个结构体中,否则为 nil

todo:目前没找到什么样的源代码解析成AST树后有Doc的

4.2. Package

*ast.File {1  .  Package: 1:12  .  Name: *ast.Ident {3  .  .  NamePos: 1:94  .  .  Name: "main"5  .  }

Package: 1:1, package关键字所在的位置

4.3. Name

img

type为ast.ident,表示它是一个变量值,可以看到内容为"main"

4.4. Decls

文件级别的声明。它包含文件中所有变量、函数、类型声明。如果文件中没有声明,则 decls 值为 nil

img

4.5. Decls总共有三种类型

img

4.5.1. BadDecl

语法出错的声明

4.5.2. GenDecl

常规的声明,包含以下部分

  • import
  • constant
  • type
  • variable
4.5.2.1. import

img

4.5.2.2. constant
4.5.2.3. type

img

4.5.2.4. variable

4.5.3. FunDecl

方法的声明

4.6. Scope

包级作用域。它代表包级作用域,包含所有在包内声明的变量和函数。它对当前文件有效

img

4.6.1. 示例如下

img

4.7. Imports

回顾以下File结构体定义,其中ImportsImportSpec类型数组

// 该结构体位于标准包 go/ast/ast.go 中,有兴趣可以转跳到源码阅读更详尽的注释
type File struct {Doc        *CommentGroup   // 如果文件有文档,则文档会被存储在这个结构体中,否则为 nilPackage    token.Pos       // "package"关键字,主要是所在的位置信息Name       *Ident          // package的名字Decls      []Decl          // 文件级别的声明。它包含文件中所有变量、函数、类型声明。如果文件中没有声明,则 decls 值为 nilScope      *Scope          // 包级作用域。它代表包级作用域,包含所有在包内声明的变量和函数。它对当前文件有效Imports    []*ImportSpec   // imports in this fileUnresolved []*Ident        // unresolved identifiers in this file。未使用的标识符Comments   []*CommentGroup // 文件中的所有注释。它包含文件中所有注释的列表
}

ImportSpec结构体定义如下,一条import就是一个ImportSpec

// An ImportSpec node represents a single package import.ImportSpec struct {Doc     *CommentGroup // associated documentation; or nilName    *Ident        // local package name (including "."); or nilPath    *BasicLit     // import pathComment *CommentGroup // line comments; or nilEndPos  token.Pos     // end of spec (overrides Path.Pos if nonzero)}

img

4.8. Unresolved

unresolved identifiers in this file。未使用的标识符

4.9. Comments

文件中的所有注释。它包含文件中所有注释的列表。实际上这块有问题,并没有注释解析出来

5. AST数节点类型

6. 参考资料

  1. Golang AST语法树使用教程及示例
  2. GoAst Viewer
  3. https://github.com/DrmagicE/ast-example
  4. [golang深入源代码系列之一:AST的遍历](

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/45772.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[杂谈] 关于 Mac 电脑使用 Logitech 鼠标导致 Vscode 侧键无法进行代码前进、回退的问题

我个人使用的是一台 14 寸的 Mac_Apple_M1,外接键盘显示器罗技的 MX Master 3 for Mac 的鼠标。 之前一直使用的 GoLand 开发,查看代码时进行代码跳转就很方便,滚轮键 进入函数方法,鼠标侧键进行前进、后退。看代码完全可以右手单…

【大模型入门】LLM-AI大模型介绍

大语言模型 (LLM) 背景 🍹大语言模型 (Large Language Model) 是一种人工智能模型, 它们通常包含数千亿甚至更多的参数,并在大规模数据集上进行训练。大语言模型可以处理多种自然语言任务,如文本分类、问答、翻译、对话等等。 自然语言模型…

qt explicit 啥意思

explicit 在 Qt 和 C 中是一个关键字,主要用于修饰类的构造函数。其含义和用法可以归纳为以下几点: 意义: explicit 英文直译为“明确的”、“显式的”。在 C 中,当一个构造函数只接受一个参数时,它可能会被编译器用于…

【Nail it】ROS1 ROS2 通信(ros2/ros1_bridge)

情况说明:目标是实现ros2容器和ros1主机的通信,可以起一个ros1容器作为桥梁(若是在一个主机同时包含ros1&ros2,配置更加方便). 1.起一个 noetic 的容器 docker run -it --network host --name my_bridge ros:noe…

Java中的成员内部类

Java中的成员内部类(也称为非静态内部类)是定义在另一个类(外部类)内部的类。 这种内部类与它的外部类之间有着紧密的联系,主要体现在几个方面:它可以访问外部类的所有成员(包括私有成员&#…

C++小白Python选手2小时入门C++

学习链接:C入门/2小时从C到C快速入门(2018,C教程) C在C语言的基础上增加了面向对象和通用算法语言特征。 C头文件不必是.h结尾,C头文件举例:cmath、cstdio注释:单行//、多行/**/为了防止名字冲…

MQ基础1

对应B站视频: MQ入门-01.MQ课程介绍_哔哩哔哩_bilibili 微服务一旦拆分,必然涉及到服务之间的相互调用,目前我们服务之间调用采用的都是基于OpenFeign的调用。这种调用中,调用者发起请求后需要等待服务提供者执行业务返回结果后…

【JavaScript脚本宇宙】强大的自然语言处理:六款JavaScript库详解

从语义到实体:深入了解JavaScript自然语言处理库 前言 随着人工智能和自然语言处理技术的飞速发展,JavaScript在这一领域也有了越来越多的应用。本文将介绍几个优秀的JavaScript库,它们专注于处理英语文本,并提供了丰富的功能和…

求立方体面积体积以及判断(c++)

代码&#xff1a; #include<iostream> using namespace std;class Cube { public:void setL(int l){m_L l;}int getL(){return m_L;}void setW(int w){m_W w;}int getW(){return m_W;}void setH(int h){m_H h;}int getH(){return m_H;}int calculateS(){return 2 * (…

netdata 监控软件安装与学习

netdata官网 netdata操作文档 前言&#xff1a; netdata是一款监控软件&#xff0c;可以监控多台主机也可以监控单台主机&#xff0c;监控单台主机时&#xff0c;开箱即用&#xff0c;web ui很棒。 环境&#xff1a; [root192 ~]# cat /etc/system-release CentOS Linux rel…

彻底清理Conda环境:使用conda remove命令的终极指南

彻底清理Conda环境&#xff1a;使用conda remove命令的终极指南 在Conda环境中&#xff0c;随着时间的推移&#xff0c;可能会积累大量不再需要的包和它们的依赖项。这不仅会占用宝贵的磁盘空间&#xff0c;还可能影响环境的性能。conda remove命令是Conda提供的一个强大工具&…

GD32F407VET6新建固件库工程并下载运行

零、所需文件及环境&#xff1a; 1、固件库的压缩包 GD32F4xx_Firmware_Library_V3.2.0.7z 官网 2、GD32F407的keil支持包 官网 兆易创新GigaDevice-资料下载兆易创新GD32 MCU 2、 keilkilll.bat 用来删除编译过程文件 可以不要 &#xff08;原子、野火资料里都有&…

LeetCode热题100(JavaScript)

哈希 两数之和 暴力解法 /*** param {number[]} nums* param {number} target* return {number[]}*/ var twoSum function(nums, target) {for(let i 0;i<nums.length;i){let x1 nums[i]for(let j 0 ; j<nums.length;j){if(i!j){let x2 nums[j]if(x1x2target){ret…

算法金 | 来了,pandas 2.0

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 今日 210/10000 Pandas 是一个强大的数据分析库&#xff0c;广泛应用于科学研究、金融分析、商业智能等领域。它提供了高效的数据结构…

[WUSTCTF2020]level4题解 入土为安的第三天

二叉树 Practice my Data Structure code..... Typing....Struct.....char....*left....*right............emmmmm...OK! Traversal! Traversal type 1:2f0t02T{hcsiI_SwA__r7Ee} Traversal type 2:20f0Th{2tsIS_icArE}e7__w Traversal type 3: //type3(&x[22]); No w…

samba服务、安装-smbpasswd工具、pdbedit工具、testparm工具

在Windows构建的网络生态里&#xff0c;各主机间的文件及打印资源共享&#xff0c;主要依赖微软专有的SMB/CIFS网络协议来达成。SMB&#xff08;即Server Message Block&#xff0c;服务消息块&#xff09;与CIFS&#xff08;全称Common Internet File System&#xff0c;通用互…

ShardingSphere的项目应用

1. 事情的起因 最近,随着业务的发展,我们的项目面临着日益增长的数据挑战。系统使用的数据库是mysql,每天的增量差不多在百万左右,由于没有进行分库分表,以前设置的单表保存已经越发不能满足需求,所以想维持表的性能,甲方考虑对这些大数据量的表进行分表操作,同时也采…

MySQL left join、right join以及inner join的区别 ?

LEFT JOIN&#xff08;左连接&#xff09;、RIGHT JOIN&#xff08;右连接&#xff09;和INNER JOIN&#xff08;内连接&#xff09;是SQL中用于连接两个或多个表以检索数据的重要操作。它们之间的主要区别在于如何处理那些在连接条件下没有匹配的行。下面通过具体的例子来说明…

扫地机器人如何解决安全性与隐私保护

扫地机器人在解决安全性与隐私保护方面&#xff0c;需要从多个角度入手&#xff0c;包括产品设计、技术实现、用户教育以及法律法规遵守等方面。以下是具体的解决方案&#xff1a; 一、安全性解决方案 1.提升避障能力&#xff1a;使用先进的传感器技术&#xff0c;如激光雷达、…

JavaScript switch 语句

JavaScript switch 语句 JavaScript 中的 switch 语句是一种多分支选择结构&#xff0c;用于根据变量的值执行不同的代码块。它提供了一种简洁的方式来替代多个 if...else 语句&#xff0c;特别是在处理多个条件时。 基本语法 switch (expression) {case value1:// 代码块 1…