
* Changes to make vendored packages accept new home. * Fix go2idl to import vendored packages.
211 lines
5.7 KiB
Go
211 lines
5.7 KiB
Go
// Copyright 2012 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package ast_test
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/format"
|
|
"go/parser"
|
|
"go/token"
|
|
)
|
|
|
|
// This example demonstrates how to inspect the AST of a Go program.
|
|
func ExampleInspect() {
|
|
// src is the input for which we want to inspect the AST.
|
|
src := `
|
|
package p
|
|
const c = 1.0
|
|
var X = f(3.14)*2 + c
|
|
`
|
|
|
|
// Create the AST by parsing src.
|
|
fset := token.NewFileSet() // positions are relative to fset
|
|
f, err := parser.ParseFile(fset, "src.go", src, 0)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Inspect the AST and print all identifiers and literals.
|
|
ast.Inspect(f, func(n ast.Node) bool {
|
|
var s string
|
|
switch x := n.(type) {
|
|
case *ast.BasicLit:
|
|
s = x.Value
|
|
case *ast.Ident:
|
|
s = x.Name
|
|
}
|
|
if s != "" {
|
|
fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s)
|
|
}
|
|
return true
|
|
})
|
|
|
|
// output:
|
|
// src.go:2:9: p
|
|
// src.go:3:7: c
|
|
// src.go:3:11: 1.0
|
|
// src.go:4:5: X
|
|
// src.go:4:9: f
|
|
// src.go:4:11: 3.14
|
|
// src.go:4:17: 2
|
|
// src.go:4:21: c
|
|
}
|
|
|
|
// This example shows what an AST looks like when printed for debugging.
|
|
func ExamplePrint() {
|
|
// src is the input for which we want to print the AST.
|
|
src := `
|
|
package main
|
|
func main() {
|
|
println("Hello, World!")
|
|
}
|
|
`
|
|
|
|
// Create the AST by parsing src.
|
|
fset := token.NewFileSet() // positions are relative to fset
|
|
f, err := parser.ParseFile(fset, "", src, 0)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Print the AST.
|
|
ast.Print(fset, f)
|
|
|
|
// output:
|
|
// 0 *ast.File {
|
|
// 1 . Package: 2:1
|
|
// 2 . Name: *ast.Ident {
|
|
// 3 . . NamePos: 2:9
|
|
// 4 . . Name: "main"
|
|
// 5 . }
|
|
// 6 . Decls: []ast.Decl (len = 1) {
|
|
// 7 . . 0: *ast.FuncDecl {
|
|
// 8 . . . Name: *ast.Ident {
|
|
// 9 . . . . NamePos: 3:6
|
|
// 10 . . . . Name: "main"
|
|
// 11 . . . . Obj: *ast.Object {
|
|
// 12 . . . . . Kind: func
|
|
// 13 . . . . . Name: "main"
|
|
// 14 . . . . . Decl: *(obj @ 7)
|
|
// 15 . . . . }
|
|
// 16 . . . }
|
|
// 17 . . . Type: *ast.FuncType {
|
|
// 18 . . . . Func: 3:1
|
|
// 19 . . . . Params: *ast.FieldList {
|
|
// 20 . . . . . Opening: 3:10
|
|
// 21 . . . . . Closing: 3:11
|
|
// 22 . . . . }
|
|
// 23 . . . }
|
|
// 24 . . . Body: *ast.BlockStmt {
|
|
// 25 . . . . Lbrace: 3:13
|
|
// 26 . . . . List: []ast.Stmt (len = 1) {
|
|
// 27 . . . . . 0: *ast.ExprStmt {
|
|
// 28 . . . . . . X: *ast.CallExpr {
|
|
// 29 . . . . . . . Fun: *ast.Ident {
|
|
// 30 . . . . . . . . NamePos: 4:2
|
|
// 31 . . . . . . . . Name: "println"
|
|
// 32 . . . . . . . }
|
|
// 33 . . . . . . . Lparen: 4:9
|
|
// 34 . . . . . . . Args: []ast.Expr (len = 1) {
|
|
// 35 . . . . . . . . 0: *ast.BasicLit {
|
|
// 36 . . . . . . . . . ValuePos: 4:10
|
|
// 37 . . . . . . . . . Kind: STRING
|
|
// 38 . . . . . . . . . Value: "\"Hello, World!\""
|
|
// 39 . . . . . . . . }
|
|
// 40 . . . . . . . }
|
|
// 41 . . . . . . . Ellipsis: -
|
|
// 42 . . . . . . . Rparen: 4:25
|
|
// 43 . . . . . . }
|
|
// 44 . . . . . }
|
|
// 45 . . . . }
|
|
// 46 . . . . Rbrace: 5:1
|
|
// 47 . . . }
|
|
// 48 . . }
|
|
// 49 . }
|
|
// 50 . Scope: *ast.Scope {
|
|
// 51 . . Objects: map[string]*ast.Object (len = 1) {
|
|
// 52 . . . "main": *(obj @ 11)
|
|
// 53 . . }
|
|
// 54 . }
|
|
// 55 . Unresolved: []*ast.Ident (len = 1) {
|
|
// 56 . . 0: *(obj @ 29)
|
|
// 57 . }
|
|
// 58 }
|
|
}
|
|
|
|
// This example illustrates how to remove a variable declaration
|
|
// in a Go program while maintaining correct comment association
|
|
// using an ast.CommentMap.
|
|
func ExampleCommentMap() {
|
|
// src is the input for which we create the AST that we
|
|
// are going to manipulate.
|
|
src := `
|
|
// This is the package comment.
|
|
package main
|
|
|
|
// This comment is associated with the hello constant.
|
|
const hello = "Hello, World!" // line comment 1
|
|
|
|
// This comment is associated with the foo variable.
|
|
var foo = hello // line comment 2
|
|
|
|
// This comment is associated with the main function.
|
|
func main() {
|
|
fmt.Println(hello) // line comment 3
|
|
}
|
|
`
|
|
|
|
// Create the AST by parsing src.
|
|
fset := token.NewFileSet() // positions are relative to fset
|
|
f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Create an ast.CommentMap from the ast.File's comments.
|
|
// This helps keeping the association between comments
|
|
// and AST nodes.
|
|
cmap := ast.NewCommentMap(fset, f, f.Comments)
|
|
|
|
// Remove the first variable declaration from the list of declarations.
|
|
f.Decls = removeFirstVarDecl(f.Decls)
|
|
|
|
// Use the comment map to filter comments that don't belong anymore
|
|
// (the comments associated with the variable declaration), and create
|
|
// the new comments list.
|
|
f.Comments = cmap.Filter(f).Comments()
|
|
|
|
// Print the modified AST.
|
|
var buf bytes.Buffer
|
|
if err := format.Node(&buf, fset, f); err != nil {
|
|
panic(err)
|
|
}
|
|
fmt.Printf("%s", buf.Bytes())
|
|
|
|
// output:
|
|
// // This is the package comment.
|
|
// package main
|
|
//
|
|
// // This comment is associated with the hello constant.
|
|
// const hello = "Hello, World!" // line comment 1
|
|
//
|
|
// // This comment is associated with the main function.
|
|
// func main() {
|
|
// fmt.Println(hello) // line comment 3
|
|
// }
|
|
}
|
|
|
|
func removeFirstVarDecl(list []ast.Decl) []ast.Decl {
|
|
for i, decl := range list {
|
|
if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR {
|
|
copy(list[i:], list[i+1:])
|
|
return list[:len(list)-1]
|
|
}
|
|
}
|
|
panic("variable declaration not found")
|
|
}
|