Home | History | Annotate | Download | only in ast
      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 		}
    180 	}
    181 
    182 	// Use the comment map to filter comments that don't belong anymore
    183 	// (the comments associated with the variable declaration), and create
    184 	// the new comments list.
    185 	f.Comments = cmap.Filter(f).Comments()
    186 
    187 	// Print the modified AST.
    188 	var buf bytes.Buffer
    189 	if err := format.Node(&buf, fset, f); err != nil {
    190 		panic(err)
    191 	}
    192 	fmt.Printf("%s", buf.Bytes())
    193 
    194 	// Output:
    195 	// // This is the package comment.
    196 	// package main
    197 	//
    198 	// // This comment is associated with the hello constant.
    199 	// const hello = "Hello, World!" // line comment 1
    200 	//
    201 	// // This comment is associated with the main function.
    202 	// func main() {
    203 	// 	fmt.Println(hello) // line comment 3
    204 	// }
    205 }
    206