]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/go/go/types/example_test.go
libgo: update to Go1.14beta1
[thirdparty/gcc.git] / libgo / go / go / types / example_test.go
CommitLineData
af146490
ILT
1// Copyright 2015 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// Only run where builders (build.golang.org) have
6// access to compiled packages for import.
7//
5a8ea165 8// +build !arm,!arm64
af146490
ILT
9
10package types_test
11
12// This file shows examples of basic usage of the go/types API.
13//
14// To locate a Go package, use (*go/build.Context).Import.
15// To load, parse, and type-check a complete Go program
16// from source, use golang.org/x/tools/go/loader.
17
18import (
19 "bytes"
20 "fmt"
21 "go/ast"
22 "go/format"
23 "go/importer"
24 "go/parser"
25 "go/token"
26 "go/types"
27 "log"
28 "regexp"
29 "sort"
30 "strings"
31)
32
33// ExampleScope prints the tree of Scopes of a package created from a
34// set of parsed files.
35func ExampleScope() {
36 // Parse the source files for a package.
37 fset := token.NewFileSet()
38 var files []*ast.File
39 for _, file := range []struct{ name, input string }{
40 {"main.go", `
41package main
42import "fmt"
43func main() {
44 freezing := FToC(-18)
45 fmt.Println(freezing, Boiling) }
46`},
47 {"celsius.go", `
48package main
49import "fmt"
50type Celsius float64
51func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
52func FToC(f float64) Celsius { return Celsius(f - 32 / 9 * 5) }
53const Boiling Celsius = 100
4f4a855d 54func Unused() { {}; {{ var x int; _ = x }} } // make sure empty block scopes get printed
af146490
ILT
55`},
56 } {
57 f, err := parser.ParseFile(fset, file.name, file.input, 0)
58 if err != nil {
59 log.Fatal(err)
60 }
61 files = append(files, f)
62 }
63
64 // Type-check a package consisting of these files.
65 // Type information for the imported "fmt" package
66 // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
67 conf := types.Config{Importer: importer.Default()}
68 pkg, err := conf.Check("temperature", fset, files, nil)
69 if err != nil {
70 log.Fatal(err)
71 }
72
73 // Print the tree of scopes.
74 // For determinism, we redact addresses.
75 var buf bytes.Buffer
76 pkg.Scope().WriteTo(&buf, 0, true)
77 rx := regexp.MustCompile(` 0x[a-fA-F0-9]*`)
78 fmt.Println(rx.ReplaceAllString(buf.String(), ""))
79
fcee6030 80 // no output for gccgo--can't import "fmt"
af146490
ILT
81 // package "temperature" scope {
82 // . const temperature.Boiling temperature.Celsius
83 // . type temperature.Celsius float64
84 // . func temperature.FToC(f float64) temperature.Celsius
4f4a855d 85 // . func temperature.Unused()
af146490 86 // . func temperature.main()
af146490
ILT
87 // . main.go scope {
88 // . . package fmt
af146490
ILT
89 // . . function scope {
90 // . . . var freezing temperature.Celsius
4f4a855d
ILT
91 // . . }
92 // . }
af146490
ILT
93 // . celsius.go scope {
94 // . . package fmt
af146490
ILT
95 // . . function scope {
96 // . . . var c temperature.Celsius
97 // . . }
98 // . . function scope {
99 // . . . var f float64
4f4a855d
ILT
100 // . . }
101 // . . function scope {
102 // . . . block scope {
103 // . . . }
104 // . . . block scope {
105 // . . . . block scope {
106 // . . . . . var x int
107 // . . . . }
108 // . . . }
109 // . . }
110 // . }
111 // }
af146490
ILT
112}
113
114// ExampleMethodSet prints the method sets of various types.
115func ExampleMethodSet() {
116 // Parse a single source file.
117 const input = `
118package temperature
119import "fmt"
120type Celsius float64
121func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
122func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
123`
124 fset := token.NewFileSet()
125 f, err := parser.ParseFile(fset, "celsius.go", input, 0)
126 if err != nil {
127 log.Fatal(err)
128 }
129
130 // Type-check a package consisting of this file.
131 // Type information for the imported packages
132 // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
133 conf := types.Config{Importer: importer.Default()}
134 pkg, err := conf.Check("temperature", fset, []*ast.File{f}, nil)
135 if err != nil {
136 log.Fatal(err)
137 }
138
139 // Print the method sets of Celsius and *Celsius.
140 celsius := pkg.Scope().Lookup("Celsius").Type()
141 for _, t := range []types.Type{celsius, types.NewPointer(celsius)} {
142 fmt.Printf("Method set of %s:\n", t)
143 mset := types.NewMethodSet(t)
144 for i := 0; i < mset.Len(); i++ {
145 fmt.Println(mset.At(i))
146 }
147 fmt.Println()
148 }
149
fcee6030 150 // no output for gccgo--can't import "fmt"
af146490
ILT
151 // Method set of temperature.Celsius:
152 // method (temperature.Celsius) String() string
153 //
154 // Method set of *temperature.Celsius:
155 // method (*temperature.Celsius) SetF(f float64)
156 // method (*temperature.Celsius) String() string
157}
158
159// ExampleInfo prints various facts recorded by the type checker in a
160// types.Info struct: definitions of and references to each named object,
161// and the type, value, and mode of every expression in the package.
162func ExampleInfo() {
163 // Parse a single source file.
164 const input = `
165package fib
166
167type S string
168
169var a, b, c = len(b), S(c), "hello"
170
171func fib(x int) int {
172 if x < 2 {
173 return x
174 }
175 return fib(x-1) - fib(x-2)
176}`
177 fset := token.NewFileSet()
178 f, err := parser.ParseFile(fset, "fib.go", input, 0)
179 if err != nil {
180 log.Fatal(err)
181 }
182
183 // Type-check the package.
184 // We create an empty map for each kind of input
185 // we're interested in, and Check populates them.
186 info := types.Info{
187 Types: make(map[ast.Expr]types.TypeAndValue),
188 Defs: make(map[*ast.Ident]types.Object),
189 Uses: make(map[*ast.Ident]types.Object),
190 }
191 var conf types.Config
192 pkg, err := conf.Check("fib", fset, []*ast.File{f}, &info)
193 if err != nil {
194 log.Fatal(err)
195 }
196
197 // Print package-level variables in initialization order.
198 fmt.Printf("InitOrder: %v\n\n", info.InitOrder)
199
200 // For each named object, print the line and
201 // column of its definition and each of its uses.
202 fmt.Println("Defs and Uses of each named object:")
203 usesByObj := make(map[types.Object][]string)
204 for id, obj := range info.Uses {
205 posn := fset.Position(id.Pos())
206 lineCol := fmt.Sprintf("%d:%d", posn.Line, posn.Column)
207 usesByObj[obj] = append(usesByObj[obj], lineCol)
208 }
209 var items []string
210 for obj, uses := range usesByObj {
211 sort.Strings(uses)
212 item := fmt.Sprintf("%s:\n defined at %s\n used at %s",
213 types.ObjectString(obj, types.RelativeTo(pkg)),
214 fset.Position(obj.Pos()),
215 strings.Join(uses, ", "))
216 items = append(items, item)
217 }
218 sort.Strings(items) // sort by line:col, in effect
219 fmt.Println(strings.Join(items, "\n"))
220 fmt.Println()
221
222 fmt.Println("Types and Values of each expression:")
223 items = nil
224 for expr, tv := range info.Types {
225 var buf bytes.Buffer
226 posn := fset.Position(expr.Pos())
227 tvstr := tv.Type.String()
228 if tv.Value != nil {
229 tvstr += " = " + tv.Value.String()
230 }
231 // line:col | expr | mode : type = value
232 fmt.Fprintf(&buf, "%2d:%2d | %-19s | %-7s : %s",
233 posn.Line, posn.Column, exprString(fset, expr),
234 mode(tv), tvstr)
235 items = append(items, buf.String())
236 }
237 sort.Strings(items)
238 fmt.Println(strings.Join(items, "\n"))
239
240 // Output:
241 // InitOrder: [c = "hello" b = S(c) a = len(b)]
242 //
243 // Defs and Uses of each named object:
244 // builtin len:
245 // defined at -
246 // used at 6:15
247 // func fib(x int) int:
248 // defined at fib.go:8:6
249 // used at 12:20, 12:9
250 // type S string:
251 // defined at fib.go:4:6
252 // used at 6:23
bc998d03 253 // type int:
af146490
ILT
254 // defined at -
255 // used at 8:12, 8:17
bc998d03 256 // type string:
af146490
ILT
257 // defined at -
258 // used at 4:8
259 // var b S:
260 // defined at fib.go:6:8
261 // used at 6:19
262 // var c string:
263 // defined at fib.go:6:11
264 // used at 6:25
265 // var x int:
266 // defined at fib.go:8:10
267 // used at 10:10, 12:13, 12:24, 9:5
268 //
269 // Types and Values of each expression:
270 // 4: 8 | string | type : string
271 // 6:15 | len | builtin : func(string) int
272 // 6:15 | len(b) | value : int
273 // 6:19 | b | var : fib.S
274 // 6:23 | S | type : fib.S
275 // 6:23 | S(c) | value : fib.S
276 // 6:25 | c | var : string
277 // 6:29 | "hello" | value : string = "hello"
278 // 8:12 | int | type : int
279 // 8:17 | int | type : int
280 // 9: 5 | x | var : int
281 // 9: 5 | x < 2 | value : untyped bool
282 // 9: 9 | 2 | value : int = 2
283 // 10:10 | x | var : int
284 // 12: 9 | fib | value : func(x int) int
285 // 12: 9 | fib(x - 1) | value : int
286 // 12: 9 | fib(x-1) - fib(x-2) | value : int
287 // 12:13 | x | var : int
288 // 12:13 | x - 1 | value : int
289 // 12:15 | 1 | value : int = 1
290 // 12:20 | fib | value : func(x int) int
291 // 12:20 | fib(x - 2) | value : int
292 // 12:24 | x | var : int
293 // 12:24 | x - 2 | value : int
294 // 12:26 | 2 | value : int = 2
295}
296
297func mode(tv types.TypeAndValue) string {
298 switch {
299 case tv.IsVoid():
300 return "void"
301 case tv.IsType():
302 return "type"
303 case tv.IsBuiltin():
304 return "builtin"
305 case tv.IsNil():
306 return "nil"
307 case tv.Assignable():
308 if tv.Addressable() {
309 return "var"
310 }
311 return "mapindex"
312 case tv.IsValue():
313 return "value"
314 default:
315 return "unknown"
316 }
317}
318
319func exprString(fset *token.FileSet, expr ast.Expr) string {
320 var buf bytes.Buffer
321 format.Node(&buf, fset, expr)
322 return buf.String()
323}