Source file src/go/ast/example_test.go
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 . . . . . . . . . ValueEnd: 4:25 117 // 38 . . . . . . . . . Kind: STRING 118 // 39 . . . . . . . . . Value: "\"Hello, World!\"" 119 // 40 . . . . . . . . } 120 // 41 . . . . . . . } 121 // 42 . . . . . . . Ellipsis: - 122 // 43 . . . . . . . Rparen: 4:25 123 // 44 . . . . . . } 124 // 45 . . . . . } 125 // 46 . . . . } 126 // 47 . . . . Rbrace: 5:1 127 // 48 . . . } 128 // 49 . . } 129 // 50 . } 130 // 51 . FileStart: 1:1 131 // 52 . FileEnd: 5:3 132 // 53 . Scope: *ast.Scope { 133 // 54 . . Objects: map[string]*ast.Object (len = 1) { 134 // 55 . . . "main": *(obj @ 11) 135 // 56 . . } 136 // 57 . } 137 // 58 . Unresolved: []*ast.Ident (len = 1) { 138 // 59 . . 0: *(obj @ 29) 139 // 60 . } 140 // 61 . GoVersion: "" 141 // 62 } 142 } 143 144 func ExamplePreorder() { 145 src := ` 146 package p 147 148 func f(x, y int) { 149 print(x + y) 150 } 151 ` 152 153 fset := token.NewFileSet() 154 f, err := parser.ParseFile(fset, "", src, 0) 155 if err != nil { 156 panic(err) 157 } 158 159 // Print identifiers in order 160 for n := range ast.Preorder(f) { 161 id, ok := n.(*ast.Ident) 162 if !ok { 163 continue 164 } 165 fmt.Println(id.Name) 166 } 167 168 // Output: 169 // p 170 // f 171 // x 172 // y 173 // int 174 // print 175 // x 176 // y 177 } 178 179 // This example illustrates how to remove a variable declaration 180 // in a Go program while maintaining correct comment association 181 // using an ast.CommentMap. 182 func ExampleCommentMap() { 183 // src is the input for which we create the AST that we 184 // are going to manipulate. 185 src := ` 186 // This is the package comment. 187 package main 188 189 // This comment is associated with the hello constant. 190 const hello = "Hello, World!" // line comment 1 191 192 // This comment is associated with the foo variable. 193 var foo = hello // line comment 2 194 195 // This comment is associated with the main function. 196 func main() { 197 fmt.Println(hello) // line comment 3 198 } 199 ` 200 201 // Create the AST by parsing src. 202 fset := token.NewFileSet() // positions are relative to fset 203 f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments) 204 if err != nil { 205 panic(err) 206 } 207 208 // Create an ast.CommentMap from the ast.File's comments. 209 // This helps keeping the association between comments 210 // and AST nodes. 211 cmap := ast.NewCommentMap(fset, f, f.Comments) 212 213 // Remove the first variable declaration from the list of declarations. 214 for i, decl := range f.Decls { 215 if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR { 216 copy(f.Decls[i:], f.Decls[i+1:]) 217 f.Decls = f.Decls[:len(f.Decls)-1] 218 break 219 } 220 } 221 222 // Use the comment map to filter comments that don't belong anymore 223 // (the comments associated with the variable declaration), and create 224 // the new comments list. 225 f.Comments = cmap.Filter(f).Comments() 226 227 // Print the modified AST. 228 var buf strings.Builder 229 if err := format.Node(&buf, fset, f); err != nil { 230 panic(err) 231 } 232 fmt.Printf("%s", buf.String()) 233 234 // Output: 235 // // This is the package comment. 236 // package main 237 // 238 // // This comment is associated with the hello constant. 239 // const hello = "Hello, World!" // line comment 1 240 // 241 // // This comment is associated with the main function. 242 // func main() { 243 // fmt.Println(hello) // line comment 3 244 // } 245 } 246