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  

View as plain text