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 "bytes" 9 "fmt" 10 "go/ast" 11 "go/format" 12 "go/parser" 13 "go/token" 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 . Scope: *ast.Scope { 130 // 51 . . Objects: map[string]*ast.Object (len = 1) { 131 // 52 . . . "main": *(obj @ 11) 132 // 53 . . } 133 // 54 . } 134 // 55 . Unresolved: []*ast.Ident (len = 1) { 135 // 56 . . 0: *(obj @ 29) 136 // 57 . } 137 // 58 } 138 } 139 140 // This example illustrates how to remove a variable declaration 141 // in a Go program while maintaining correct comment association 142 // using an ast.CommentMap. 143 func ExampleCommentMap() { 144 // src is the input for which we create the AST that we 145 // are going to manipulate. 146 src := ` 147 // This is the package comment. 148 package main 149 150 // This comment is associated with the hello constant. 151 const hello = "Hello, World!" // line comment 1 152 153 // This comment is associated with the foo variable. 154 var foo = hello // line comment 2 155 156 // This comment is associated with the main function. 157 func main() { 158 fmt.Println(hello) // line comment 3 159 } 160 ` 161 162 // Create the AST by parsing src. 163 fset := token.NewFileSet() // positions are relative to fset 164 f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments) 165 if err != nil { 166 panic(err) 167 } 168 169 // Create an ast.CommentMap from the ast.File's comments. 170 // This helps keeping the association between comments 171 // and AST nodes. 172 cmap := ast.NewCommentMap(fset, f, f.Comments) 173 174 // Remove the first variable declaration from the list of declarations. 175 for i, decl := range f.Decls { 176 if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR { 177 copy(f.Decls[i:], f.Decls[i+1:]) 178 f.Decls = f.Decls[:len(f.Decls)-1] 179 break 180 } 181 } 182 183 // Use the comment map to filter comments that don't belong anymore 184 // (the comments associated with the variable declaration), and create 185 // the new comments list. 186 f.Comments = cmap.Filter(f).Comments() 187 188 // Print the modified AST. 189 var buf bytes.Buffer 190 if err := format.Node(&buf, fset, f); err != nil { 191 panic(err) 192 } 193 fmt.Printf("%s", buf.Bytes()) 194 195 // Output: 196 // // This is the package comment. 197 // package main 198 // 199 // // This comment is associated with the hello constant. 200 // const hello = "Hello, World!" // line comment 1 201 // 202 // // This comment is associated with the main function. 203 // func main() { 204 // fmt.Println(hello) // line comment 3 205 // } 206 } 207