Unleash the Potential of Your Go Code with go ast
and Automation
Contact Author@:Medium,LinkedIn,Twitter
Hello, here is Wesley, Today’s article is about ast in Go. Without further ado, let’s get started.💪
Recently, I learned about using stringer
and stumbled upon related content for golang ast
, which led me to discover that I can also write some Go-related automation tools.
1.1 stringer and go generate
In development, we often need to define error codes with unique identifiers for specific error information. Additionally, we need to set the description for each error code. For example, in HTTP protocol, 200 represents “OK”, while 404 represents “Not Found”.
Traditionally, when defining error codes, we would also need to add a description, which is often forgotten and makes maintenance difficult. However, we can elegantly solve this problem using go generate
+ stringer
toolchain.
stringer usage:
1 | Usage of stringer: |
Example:
1 | package main |
Running go generate
generates the following code:
1 | // Code generated by "stringer -type ErrCode -trimprefix ERR_CODE -output code_string.go"; DO NOT EDIT. |
The go generate
command can be used after reading the article Generating code - The Go Programming Language and running go help generate
to see basic usage.
1.2 How does stringer implement automatic generation?
Source code implementation: stringer.go
1 | import ( |
The main parts are “flag” and “go/ast”, “go/token”. The “flag” package mainly handles some command-line arguments, which can be referred to in my article: Flag Package You should Know in Golang | by Wesley Wei | Programmer’s Career.
The key point is to understand “go/ast”, which is a powerful tool for processing source code in the Go language. It not only simplifies the process of analyzing code, but also provides strong support for code generation and reconstruction.
1.3 Abstract Syntax Tree (AST)
Those who have studied compiler theory may be familiar with the front-end and back-end of a compiler. The front-end typically handles lexical analysis, syntax analysis, type checking, and intermediate code generation, while the back-end mainly focuses on generating and optimizing target code, which is translating intermediate code into binary machine code that can be executed by the target machine.
However, for those who are not familiar with compilers, we only need to understand the front-end part, which does not involve the back-end. Additionally, the official Go library go/ast
provides a ready-to-use package.
1.3.1 Concept and Applications
An Abstract Syntax Tree (AST) is a tree-like data structure used to represent the syntactic structure of source code. AST breaks down the source code into nodes with hierarchical structures, where each node represents a syntactic element in the code, such as expressions, statements, variables, etc.
AST has wide applications in compilers and analysis tools:
- Code Analysis: The compiler converts the source code to an AST, providing a foundation for subsequent code analysis and optimization.
- Code Analysis and Checking: By traversing the AST, you can check the code for errors or improvement points using static analysis tools or code checking tools.
- Code Transformation and Optimization: By modifying the AST, you can implement automatic code optimization and transformation, such as code formatting tools.
- Code Generation: You can write code generation tools to generate new source code files or intermediate code.
1.3.2 How to Generate and Use AST in Go
In the Go language, we mainly use the following three standard libraries to generate and operate on AST:
go/parser
: Used to parse Go source code and generate an AST.go/token
: Used to manage the positions and tokens of the source code.go/ast
: Used to represent and operate on the AST.
We can use the parser.ParseFile
function to parse a file and generate an AST. Here is a simple example:
1 | package main |
output:
1 | 0 *ast.File { |
Common Node Types
ast.File
: Represents a source file.ast.GenDecl
: Represents general declarations (such as imports, constants, variables, type declarations).ast.FuncDecl
: Represents function declarations.ast.BlockStmt
: Represents code blocks.ast.Expr
: The base node type for all expressions, such as literals and binary expressions.ast.Stmt
: The base node type for all statements, such as assignment statements and return statements.
For example, the *ast.FuncDecl
output represents a function definition with the name main
. The content is quite extensive, so you can refer to ast.go; l=972 for more information.
1.3.3 Traversing and Visiting AST Nodes
After generating the AST, you can traverse and visit each node. For example, the following code shows how to traverse the AST and extract the desired content:
1 | package main |
Output:
1 | Package: main |
1.4 Actual Applications
1.4.1 Code Inspection
Code inspection is an essential part of static analysis, which can help detect potential issues or optimize code. By traversing the Abstract Syntax Tree (AST), we can write custom rules to inspect code.
The following example demonstrates how to use AST to check for unused variables:
1 | package main |
1.4.2 Code Formatting
Code formatting is an important part of ensuring code style consistency. By using AST, we can reorganize the code to conform to predetermined format rules.
The following example demonstrates how to use AST to add comments for each function:
1 | package main |
1.4.3 Comment Handling
Comment handling can be used for tasks such as extracting documentation and generating code. By traversing AST, we can collect and process comments in the code.
The following example demonstrates how to extract and print all comments:
1 | package main |
1.4.4 Concrete Examples in Go
You must have thought of some Go tools after seeing the previous examples.
In Go, many tools are implemented based on the go/ast
(Abstract Syntax Tree) library, which is used to parse and analyze Go source code. Here are a few common tools that use go/ast
:
gofmt
gofmt
is a built-in code formatting tool for Go, which formats Go code into a standard style. It usesgo/ast
to analyze the code structure and convert it into a uniform format.- For example,
gofmt
automatically performs indentation, alignment, and whitespace operations to ensure consistency and readability of Go code.
go vet
go vet
is a static code analysis tool that can detect potential errors or non-compliant usage in code. By analyzing the code usinggo/ast
,go vet
can detect common errors such as mismatchedPrintf
parameters, incorrect lock operations, and more.
golint
golint
is a code linting tool for Go that helps developers follow Go’s coding conventions. It usesgo/ast
to analyze the code and find non-compliant coding patterns, such as unnamed exported structures or naming conventions not followed.
go doc
go doc
is a documentation tool for Go that usesgo/ast
to analyze code comments and generate function, method, type, and other documentation information.- This makes it possible for
go doc
to provide convenient documentation viewing options, especially for local code libraries.
gorename
gorename
is a renaming tool that allows developers to safely rename Go code identifiers. It usesgo/ast
to analyze the code structure and dependencies, ensuring all references can be safely renamed.
stringer
stringer
is an official Go code generation tool specifically designed for generating string representations of enumeration types. It usesgo/ast
to parse constant definitions in code and generate related string methods, making it easier to debug output and log recording in code.
These tools, based on go/ast
, provide structured analysis capabilities for Go code, enabling functions such as formatting, static checking, documentation generation, and code generation.
1.5 Other Applications of AST Tools
We will introduce two projects, pingcap’s failpoint and Uber-go’s gopatch.
The usage of failpoint is to implement the Marker
function in code. These functions are optimized away by the compiler at normal compilation time, so there is no extra overhead during normal runtime:
1 | var outerVar = "declare in outer scope" |
When fault injection occurs, the Marker
function is converted to a fault injection function using go ast
.
Uber-go’s gopatch
is also very powerful. For example, if your code has many go func
-opened goroutines and you want to batch in recover
logic, it can be tedious to do this manually. At this time, you can use gopatcher:
1 | var patchTemplateString = `@@ |
You can write a template like this:
1 | package main |
This example can automatically inject the recover
statement block at the beginning of go func(…) {
, which is very convenient.
Of course, gopatch
can do many things, and you can explore it freely.
1.6 Conclusion
The above content introduced the basic usage of go ast
and some mature tools, but in actual work, you will encounter scenarios that are between these two extremes, such as custom error codes, standard HTTP error codes being too few for a large-scale service, so you can write an automated tool to generate custom error codes.
Of course, automated tools are only extremely useful when dealing with a large amount of redundant work, as they can help us save labor and maintain focus.
In summary, the go ast
library provides developers with a lot of space to handle Go code, mastering AST usage can enable more efficient code analysis and tool development.
More Series Articles about You Should Know In Golang:
https://wesley-wei.medium.com/list/you-should-know-in-golang-e9491363cd9a
And I’m Wesley, delighted to share knowledge from the world of programming.
Don’t forget to follow me for more informative content, or feel free to share this with others who may also find it beneficial. it would be a great help to me.
Give me some free applauds, highlights, or replies, and I’ll pay attention to those reactions, which will determine whether or not I continue to post this type of article.
See you in the next article. 👋
中文文章: https://programmerscareer.com/zh-cn/golang-ast/
Author: Medium,LinkedIn,Twitter
Note: Originally written at https://programmerscareer.com/golang-ast/ at 2024-10-26 20:28.
Copyright: BY-NC-ND 3.0
Comments