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  }