1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ast_test 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/format" 11 "go/parser" 12 "go/token" 13 "strings" 14 ) 15 16 // This example demonstrates how to inspect the AST of a Go program. 17 func ExampleInspect() { 18 // src is the input for which we want to inspect the AST. 19 src := ` 20 package p 21 const c = 1.0 22 var X = f(3.14)*2 + c 23 ` 24 25 // Create the AST by parsing src. 26 fset := token.NewFileSet() // positions are relative to fset 27 f, err := parser.ParseFile(fset, "src.go", src, 0) 28 if err != nil { 29 panic(err) 30 } 31 32 // Inspect the AST and print all identifiers and literals. 33 ast.Inspect(f, func(n ast.Node) bool { 34 var s string 35 switch x := n.(type) { 36 case *ast.BasicLit: 37 s = x.Value 38 case *ast.Ident: 39 s = x.Name 40 } 41 if s != "" { 42 fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s) 43 } 44 return true 45 }) 46 47 // Output: 48 // src.go:2:9: p 49 // src.go:3:7: c 50 // src.go:3:11: 1.0 51 // src.go:4:5: X 52 // src.go:4:9: f 53 // src.go:4:11: 3.14 54 // src.go:4:17: 2 55 // src.go:4:21: c 56 } 57 58 // This example shows what an AST looks like when printed for debugging. 59 func ExamplePrint() { 60 // src is the input for which we want to print the AST. 61 src := ` 62 package main 63 func main() { 64 println("Hello, World!") 65 } 66 ` 67 68 // Create the AST by parsing src. 69 fset := token.NewFileSet() // positions are relative to fset 70 f, err := parser.ParseFile(fset, "", src, 0) 71 if err != nil { 72 panic(err) 73 } 74 75 // Print the AST. 76 ast.Print(fset, f) 77 78 // Output: 79 // 0 *ast.File { 80 // 1 . Package: 2:1 81 // 2 . Name: *ast.Ident { 82 // 3 . . NamePos: 2:9 83 // 4 . . Name: "main" 84 // 5 . } 85 // 6 . Decls: []ast.Decl (len = 1) { 86 // 7 . . 0: *ast.FuncDecl { 87 // 8 . . . Name: *ast.Ident { 88 // 9 . . . . NamePos: 3:6 89 // 10 . . . . Name: "main" 90 // 11 . . . . Obj: *ast.Object { 91 // 12 . . . . . Kind: func 92 // 13 . . . . . Name: "main" 93 // 14 . . . . . Decl: *(obj @ 7) 94 // 15 . . . . } 95 // 16 . . . } 96 // 17 . . . Type: *ast.FuncType { 97 // 18 . . . . Func: 3:1 98 // 19 . . . . Params: *ast.FieldList { 99 // 20 . . . . . Opening: 3:10 100 // 21 . . . . . Closing: 3:11 101 // 22 . . . . } 102 // 23 . . . } 103 // 24 . . . Body: *ast.BlockStmt { 104 // 25 . . . . Lbrace: 3:13 105 // 26 . . . . List: []ast.Stmt (len = 1) { 106 // 27 . . . . . 0: *ast.ExprStmt { 107 // 28 . . . . . . X: *ast.CallExpr { 108 // 29 . . . . . . . Fun: *ast.Ident { 109 // 30 . . . . . . . . NamePos: 4:2 110 // 31 . . . . . . . . Name: "println" 111 // 32 . . . . . . . } 112 // 33 . . . . . . . Lparen: 4:9 113 // 34 . . . . . . . Args: []ast.Expr (len = 1) { 114 // 35 . . . . . . . . 0: *ast.BasicLit { 115 // 36 . . . . . . . . . ValuePos: 4:10 116 // 37 . . . . . . . . . Kind: STRING 117 // 38 . . . . . . . . . Value: "\"Hello, World!\"" 118 // 39 . . . . . . . . } 119 // 40 . . . . . . . } 120 // 41 . . . . . . . Ellipsis: - 121 // 42 . . . . . . . Rparen: 4:25 122 // 43 . . . . . . } 123 // 44 . . . . . } 124 // 45 . . . . } 125 // 46 . . . . Rbrace: 5:1 126 // 47 . . . } 127 // 48 . . } 128 // 49 . } 129 // 50 . FileStart: 1:1 130 // 51 . FileEnd: 5:3 131 // 52 . Scope: *ast.Scope { 132 // 53 . . Objects: map[string]*ast.Object (len = 1) { 133 // 54 . . . "main": *(obj @ 11) 134 // 55 . . } 135 // 56 . } 136 // 57 . Unresolved: []*ast.Ident (len = 1) { 137 // 58 . . 0: *(obj @ 29) 138 // 59 . } 139 // 60 . GoVersion: "" 140 // 61 } 141 } 142 143 func ExamplePreorder() { 144 src := ` 145 package p 146 147 func f(x, y int) { 148 print(x + y) 149 } 150 ` 151 152 fset := token.NewFileSet() 153 f, err := parser.ParseFile(fset, "", src, 0) 154 if err != nil { 155 panic(err) 156 } 157 158 // Print identifiers in order 159 for n := range ast.Preorder(f) { 160 id, ok := n.(*ast.Ident) 161 if !ok { 162 continue 163 } 164 fmt.Println(id.Name) 165 } 166 167 // Output: 168 // p 169 // f 170 // x 171 // y 172 // int 173 // print 174 // x 175 // y 176 } 177 178 // This example illustrates how to remove a variable declaration 179 // in a Go program while maintaining correct comment association 180 // using an ast.CommentMap. 181 func ExampleCommentMap() { 182 // src is the input for which we create the AST that we 183 // are going to manipulate. 184 src := ` 185 // This is the package comment. 186 package main 187 188 // This comment is associated with the hello constant. 189 const hello = "Hello, World!" // line comment 1 190 191 // This comment is associated with the foo variable. 192 var foo = hello // line comment 2 193 194 // This comment is associated with the main function. 195 func main() { 196 fmt.Println(hello) // line comment 3 197 } 198 ` 199 200 // Create the AST by parsing src. 201 fset := token.NewFileSet() // positions are relative to fset 202 f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments) 203 if err != nil { 204 panic(err) 205 } 206 207 // Create an ast.CommentMap from the ast.File's comments. 208 // This helps keeping the association between comments 209 // and AST nodes. 210 cmap := ast.NewCommentMap(fset, f, f.Comments) 211 212 // Remove the first variable declaration from the list of declarations. 213 for i, decl := range f.Decls { 214 if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR { 215 copy(f.Decls[i:], f.Decls[i+1:]) 216 f.Decls = f.Decls[:len(f.Decls)-1] 217 break 218 } 219 } 220 221 // Use the comment map to filter comments that don't belong anymore 222 // (the comments associated with the variable declaration), and create 223 // the new comments list. 224 f.Comments = cmap.Filter(f).Comments() 225 226 // Print the modified AST. 227 var buf strings.Builder 228 if err := format.Node(&buf, fset, f); err != nil { 229 panic(err) 230 } 231 fmt.Printf("%s", buf.String()) 232 233 // Output: 234 // // This is the package comment. 235 // package main 236 // 237 // // This comment is associated with the hello constant. 238 // const hello = "Hello, World!" // line comment 1 239 // 240 // // This comment is associated with the main function. 241 // func main() { 242 // fmt.Println(hello) // line comment 3 243 // } 244 } 245