github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/go/types/example_test.go (about) 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 // ビルダー(build.golang.org)がコンパイルされたパッケージにアクセスできる場所でのみ実行する。 6 // 7 //go:build !android && !ios && !js && !wasip1 8 9 package types_test 10 11 import ( 12 "github.com/shogo82148/std/fmt" 13 "github.com/shogo82148/std/go/ast" 14 "github.com/shogo82148/std/go/importer" 15 "github.com/shogo82148/std/go/parser" 16 "github.com/shogo82148/std/go/token" 17 "github.com/shogo82148/std/go/types" 18 "github.com/shogo82148/std/log" 19 "github.com/shogo82148/std/regexp" 20 "github.com/shogo82148/std/sort" 21 "github.com/shogo82148/std/strings" 22 ) 23 24 // ExampleScope は解析されたファイルの集まりから作成されたパッケージのスコープのツリーを出力します。 25 func ExampleScope() { 26 // パッケージのソースファイルを解析する。 27 fset := token.NewFileSet() 28 var files []*ast.File 29 for _, src := range []string{ 30 `package main 31 import "fmt" 32 func main() { 33 freezing := FToC(-18) 34 fmt.Println(freezing, Boiling) } 35 `, 36 `package main 37 import "fmt" 38 type Celsius float64 39 func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) } 40 func FToC(f float64) Celsius { return Celsius(f - 32 / 9 * 5) } 41 const Boiling Celsius = 100 42 func Unused() { {}; {{ var x int; _ = x }} } // make sure empty block scopes get printed 43 `, 44 } { 45 files = append(files, mustParse(fset, src)) 46 } 47 48 // これらのファイルから成るパッケージの型チェックを行います。 49 // インポートされた "fmt" パッケージの型情報は、$GOROOT/pkg/$GOOS_$GOOARCH/fmt.a から取得されます。 50 conf := types.Config{Importer: importer.Default()} 51 pkg, err := conf.Check("temperature", fset, files, nil) 52 if err != nil { 53 log.Fatal(err) 54 } 55 56 // スコープツリーを表示します。 57 // 同一性を確保するために、アドレスは非表示にします。 58 var buf strings.Builder 59 pkg.Scope().WriteTo(&buf, 0, true) 60 rx := regexp.MustCompile(` 0x[a-fA-F\d]*`) 61 fmt.Println(rx.ReplaceAllString(buf.String(), "")) 62 63 // Output: 64 // package "temperature" scope { 65 // . const temperature.Boiling temperature.Celsius 66 // . type temperature.Celsius float64 67 // . func temperature.FToC(f float64) temperature.Celsius 68 // . func temperature.Unused() 69 // . func temperature.main() 70 // . main scope { 71 // . . package fmt 72 // . . function scope { 73 // . . . var freezing temperature.Celsius 74 // . . } 75 // . } 76 // . main scope { 77 // . . package fmt 78 // . . function scope { 79 // . . . var c temperature.Celsius 80 // . . } 81 // . . function scope { 82 // . . . var f float64 83 // . . } 84 // . . function scope { 85 // . . . block scope { 86 // . . . } 87 // . . . block scope { 88 // . . . . block scope { 89 // . . . . . var x int 90 // . . . . } 91 // . . . } 92 // . . } 93 // . } 94 // } 95 } 96 97 // ExampleMethodSet は様々な型のメソッドセットを表示します。 98 func ExampleMethodSet() { 99 // 1つのソースファイルを解析する。 100 const input = ` 101 package temperature 102 import "fmt" 103 type Celsius float64 104 func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) } 105 func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) } 106 107 type S struct { I; m int } 108 type I interface { m() byte } 109 ` 110 fset := token.NewFileSet() 111 f, err := parser.ParseFile(fset, "celsius.go", input, 0) 112 if err != nil { 113 log.Fatal(err) 114 } 115 116 // このファイルからなるパッケージを型チェックします。 117 // インポートされたパッケージの型情報は、$GOROOT/pkg/$GOOS_$GOOARCH/fmt.a から来ます。 118 conf := types.Config{Importer: importer.Default()} 119 pkg, err := conf.Check("temperature", fset, []*ast.File{f}, nil) 120 if err != nil { 121 log.Fatal(err) 122 } 123 124 // Celsiusと*Celsiusのメソッドセットを表示する。 125 celsius := pkg.Scope().Lookup("Celsius").Type() 126 for _, t := range []types.Type{celsius, types.NewPointer(celsius)} { 127 fmt.Printf("Method set of %s:\n", t) 128 mset := types.NewMethodSet(t) 129 for i := 0; i < mset.Len(); i++ { 130 fmt.Println(mset.At(i)) 131 } 132 fmt.Println() 133 } 134 135 // Sのメソッドセットを出力する。 136 styp := pkg.Scope().Lookup("S").Type() 137 fmt.Printf("Method set of %s:\n", styp) 138 fmt.Println(types.NewMethodSet(styp)) 139 140 // Output: 141 // Method set of temperature.Celsius: 142 // method (temperature.Celsius) String() string 143 // 144 // Method set of *temperature.Celsius: 145 // method (*temperature.Celsius) SetF(f float64) 146 // method (*temperature.Celsius) String() string 147 // 148 // Method set of temperature.S: 149 // MethodSet {} 150 } 151 152 // ExampleInfoは、型チェッカーによって型構造体(types.Info)に記録されたさまざまな事実を出力します。名前付きオブジェクトの定義と参照、パッケージ内のすべての式の型、値、モードなどが含まれます。 153 func ExampleInfo() { 154 // 1つのソースファイルを解析する。 155 const input = ` 156 package fib 157 158 type S string 159 160 var a, b, c = len(b), S(c), "hello" 161 162 func fib(x int) int { 163 if x < 2 { 164 return x 165 } 166 return fib(x-1) - fib(x-2) 167 }` 168 169 // このテストでは、位置情報のために特定のファイルセットが必要です。 170 // 型チェックのヘルパーは使用できません。 171 fset := token.NewFileSet() 172 f := mustParse(fset, input) 173 174 // パッケージの型チェックを行います。 175 // 我々は興味のある各種類の入力に対して空のマップを作成し、Checkがそれらを埋め込みます。 176 info := types.Info{ 177 Types: make(map[ast.Expr]types.TypeAndValue), 178 Defs: make(map[*ast.Ident]types.Object), 179 Uses: make(map[*ast.Ident]types.Object), 180 } 181 var conf types.Config 182 pkg, err := conf.Check("fib", fset, []*ast.File{f}, &info) 183 if err != nil { 184 log.Fatal(err) 185 } 186 187 // 初期化順にパッケージレベルの変数を表示する。 188 fmt.Printf("InitOrder: %v\n\n", info.InitOrder) 189 190 // 各名前付きオブジェクトについて、その定義の行と列、およびそれぞれの使用箇所を出力します。 191 fmt.Println("Defs and Uses of each named object:") 192 usesByObj := make(map[types.Object][]string) 193 for id, obj := range info.Uses { 194 posn := fset.Position(id.Pos()) 195 lineCol := fmt.Sprintf("%d:%d", posn.Line, posn.Column) 196 usesByObj[obj] = append(usesByObj[obj], lineCol) 197 } 198 var items []string 199 for obj, uses := range usesByObj { 200 sort.Strings(uses) 201 item := fmt.Sprintf("%s:\n defined at %s\n used at %s", 202 types.ObjectString(obj, types.RelativeTo(pkg)), 203 fset.Position(obj.Pos()), 204 strings.Join(uses, ", ")) 205 items = append(items, item) 206 } 207 sort.Strings(items) // 行:列によるソート、実質的には 208 fmt.Println(strings.Join(items, "\n")) 209 fmt.Println() 210 211 fmt.Println("Types and Values of each expression:") 212 items = nil 213 for expr, tv := range info.Types { 214 var buf strings.Builder 215 posn := fset.Position(expr.Pos()) 216 tvstr := tv.Type.String() 217 if tv.Value != nil { 218 tvstr += " = " + tv.Value.String() 219 } 220 // 行:列 | 式 | モード:型 = 値 221 fmt.Fprintf(&buf, "%2d:%2d | %-19s | %-7s : %s", 222 posn.Line, posn.Column, exprString(fset, expr), 223 mode(tv), tvstr) 224 items = append(items, buf.String()) 225 } 226 sort.Strings(items) 227 fmt.Println(strings.Join(items, "\n")) 228 229 // Output: 230 // InitOrder: [c = "hello" b = S(c) a = len(b)] 231 // 232 // Defs and Uses of each named object: 233 // builtin len: 234 // defined at - 235 // used at 6:15 236 // func fib(x int) int: 237 // defined at fib:8:6 238 // used at 12:20, 12:9 239 // type S string: 240 // defined at fib:4:6 241 // used at 6:23 242 // type int: 243 // defined at - 244 // used at 8:12, 8:17 245 // type string: 246 // defined at - 247 // used at 4:8 248 // var b S: 249 // defined at fib:6:8 250 // used at 6:19 251 // var c string: 252 // defined at fib:6:11 253 // used at 6:25 254 // var x int: 255 // defined at fib:8:10 256 // used at 10:10, 12:13, 12:24, 9:5 257 // 258 // Types and Values of each expression: 259 // 4: 8 | string | type : string 260 // 6:15 | len | builtin : func(fib.S) int 261 // 6:15 | len(b) | value : int 262 // 6:19 | b | var : fib.S 263 // 6:23 | S | type : fib.S 264 // 6:23 | S(c) | value : fib.S 265 // 6:25 | c | var : string 266 // 6:29 | "hello" | value : string = "hello" 267 // 8:12 | int | type : int 268 // 8:17 | int | type : int 269 // 9: 5 | x | var : int 270 // 9: 5 | x < 2 | value : untyped bool 271 // 9: 9 | 2 | value : int = 2 272 // 10:10 | x | var : int 273 // 12: 9 | fib | value : func(x int) int 274 // 12: 9 | fib(x - 1) | value : int 275 // 12: 9 | fib(x-1) - fib(x-2) | value : int 276 // 12:13 | x | var : int 277 // 12:13 | x - 1 | value : int 278 // 12:15 | 1 | value : int = 1 279 // 12:20 | fib | value : func(x int) int 280 // 12:20 | fib(x - 2) | value : int 281 // 12:24 | x | var : int 282 // 12:24 | x - 2 | value : int 283 // 12:26 | 2 | value : int = 2 284 }