Astextract
Convert a go file to its ast representation
Install / Use
/learn @luantak/AstextractREADME
astextract
astextract converts a given go file to its ast representation.
This is useful for easliy writing typesafe go generate tools, which don't concatenate strings for generating code.
The output of astextract is 100% valid go, so it can be used in go code directly without any modifications.
All zero/null value struct fields are ommited for a more compact ast representation.
Absolute Position info is stripped, because positions change if you add any dynamic content to the ast.
I already wrote binclude a tool for resource embedding with the help of astextraxt, and added string obfuscation to garble.
Web app
astextract be used as a Web app: https://astextract.lu4p.xyz/
The Web app was created using the amazing go-app package.
Install
GO111MODULE=on go get -u github.com/lu4p/astextract/cmd/astextract
Usage
astextract [flags] file
See astextract -h for up to date usage information.
Example
main.go:
package main
func main() {
println("Hello, World!")
}
Command: astextract main.go
Output:
&ast.File {
Package: 1,
Name: &ast.Ident {
Name: "main",
},
Decls: []ast.Decl {
&ast.FuncDecl {
Name: &ast.Ident {
Name: "main",
},
Type: &ast.FuncType {
Params: &ast.FieldList {},
},
Body: &ast.BlockStmt {
List: []ast.Stmt {
&ast.ExprStmt {
X: &ast.CallExpr {
Fun: &ast.Ident {
Name: "println",
},
Args: []ast.Expr {
&ast.BasicLit {
Kind: token.STRING,
Value: "\"Hello, World!\"",
},
},
},
},
},
},
},
},
}
How to convert go/ast back to go
Example taken from binclude generateFile()
bincludeFile := &ast.File{
Doc: &ast.CommentGroup{
List: []*ast.Comment{
{
Slash: 1,
Text: "// Code generated by binclude; DO NOT EDIT.",
},
},
},
Package: 45,
Name: pkgName,
Decls: []ast.Decl{
&ast.GenDecl{
Tok: token.IMPORT,
Specs: imports,
},
&ast.GenDecl{
Tok: token.VAR,
Specs: astVars,
},
},
}
f, err := os.OpenFile("binclude.go", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()
err = printer.Fprint(f, fset, bincludeFile)
if err != nil {
return err
}
astextract -out=filename main.go generates a go file containing the ast of main.go and an example on how to generate go code from the ast.
Alternatives
- go2ast: only converts a single line and doesn't support top level definitions.
- go/ast Print: prints a representation which is unsuitable for usage in code generation
From the go/ast documentation:
This example shows what an AST looks like when printed for debugging. Code:
// src is the input for which we want to print the AST.
src := `
package main
func main() {
println("Hello, World!")
}
`
// Create the AST by parsing src.
fset := token.NewFileSet() // positions are relative to fset
f, err := parser.ParseFile(fset, "", src, 0)
if err != nil {
panic(err)
}
// Print the AST.
ast.Print(fset, f)
Output:
0 *ast.File {
1 . Package: 2:1
2 . Name: *ast.Ident {
3 . . NamePos: 2:9
4 . . Name: "main"
5 . }
6 . Decls: []ast.Decl (len = 1) {
7 . . 0: *ast.FuncDecl {
8 . . . Name: *ast.Ident {
9 . . . . NamePos: 3:6
10 . . . . Name: "main"
11 . . . . Obj: *ast.Object {
12 . . . . . Kind: func
13 . . . . . Name: "main"
14 . . . . . Decl: *(obj @ 7)
15 . . . . }
16 . . . }
17 . . . Type: *ast.FuncType {
18 . . . . Func: 3:1
19 . . . . Params: *ast.FieldList {
20 . . . . . Opening: 3:10
21 . . . . . Closing: 3:11
22 . . . . }
23 . . . }
24 . . . Body: *ast.BlockStmt {
25 . . . . Lbrace: 3:13
26 . . . . List: []ast.Stmt (len = 1) {
27 . . . . . 0: *ast.ExprStmt {
28 . . . . . . X: *ast.CallExpr {
29 . . . . . . . Fun: *ast.Ident {
30 . . . . . . . . NamePos: 4:2
31 . . . . . . . . Name: "println"
32 . . . . . . . }
33 . . . . . . . Lparen: 4:9
34 . . . . . . . Args: []ast.Expr (len = 1) {
35 . . . . . . . . 0: *ast.BasicLit {
36 . . . . . . . . . ValuePos: 4:10
37 . . . . . . . . . Kind: STRING
38 . . . . . . . . . Value: "\"Hello, World!\""
39 . . . . . . . . }
40 . . . . . . . }
41 . . . . . . . Ellipsis: -
42 . . . . . . . Rparen: 4:25
43 . . . . . . }
44 . . . . . }
45 . . . . }
46 . . . . Rbrace: 5:1
47 . . . }
48 . . }
49 . }
50 . Scope: *ast.Scope {
51 . . Objects: map[string]*ast.Object (len = 1) {
52 . . . "main": *(obj @ 11)
53 . . }
54 . }
55 . Unresolved: []*ast.Ident (len = 1) {
56 . . 0: *(obj @ 29)
57 . }
58 }
Related Skills
node-connect
349.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
xurl
349.2kA CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.
frontend-design
109.5kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
