| package main |
| |
| import ( |
| "bytes" |
| "fmt" |
| "go/ast" |
| "go/format" |
| "go/importer" |
| "go/parser" |
| "go/token" |
| "go/types" |
| "log" |
| ) |
| |
| // !+input |
| const input = ` |
| package main |
| |
| var m = make(map[string]int) |
| |
| func main() { |
| v, ok := m["hello, " + "world"] |
| print(rune(v), ok) |
| } |
| ` |
| |
| //!-input |
| |
| var fset = token.NewFileSet() |
| |
| func main() { |
| f, err := parser.ParseFile(fset, "hello.go", input, 0) |
| if err != nil { |
| log.Fatal(err) // parse error |
| } |
| |
| conf := types.Config{Importer: importer.Default()} |
| info := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)} |
| if _, err := conf.Check("cmd/hello", fset, []*ast.File{f}, info); err != nil { |
| log.Fatal(err) // type error |
| } |
| |
| //!+inspect |
| // f is a parsed, type-checked *ast.File. |
| ast.Inspect(f, func(n ast.Node) bool { |
| if expr, ok := n.(ast.Expr); ok { |
| if tv, ok := info.Types[expr]; ok { |
| fmt.Printf("%-24s\tmode: %s\n", nodeString(expr), mode(tv)) |
| fmt.Printf("\t\t\t\ttype: %v\n", tv.Type) |
| if tv.Value != nil { |
| fmt.Printf("\t\t\t\tvalue: %v\n", tv.Value) |
| } |
| } |
| } |
| return true |
| }) |
| //!-inspect |
| } |
| |
| // nodeString formats a syntax tree in the style of gofmt. |
| func nodeString(n ast.Node) string { |
| var buf bytes.Buffer |
| format.Node(&buf, fset, n) |
| return buf.String() |
| } |
| |
| // mode returns a string describing the mode of an expression. |
| func mode(tv types.TypeAndValue) string { |
| s := "" |
| if tv.IsVoid() { |
| s += ",void" |
| } |
| if tv.IsType() { |
| s += ",type" |
| } |
| if tv.IsBuiltin() { |
| s += ",builtin" |
| } |
| if tv.IsValue() { |
| s += ",value" |
| } |
| if tv.IsNil() { |
| s += ",nil" |
| } |
| if tv.Addressable() { |
| s += ",addressable" |
| } |
| if tv.Assignable() { |
| s += ",assignable" |
| } |
| if tv.HasOk() { |
| s += ",ok" |
| } |
| return s[1:] |
| } |
| |
| /* |
| //!+output |
| $ go build golang.org/x/example/gotypes/typeandvalue |
| $ ./typeandvalue |
| make(map[string]int) mode: value |
| type: map[string]int |
| make mode: builtin |
| type: func(map[string]int) map[string]int |
| map[string]int mode: type |
| type: map[string]int |
| string mode: type |
| type: string |
| int mode: type |
| type: int |
| m["hello, "+"world"] mode: value,assignable,ok |
| type: (int, bool) |
| m mode: value,addressable,assignable |
| type: map[string]int |
| "hello, " + "world" mode: value |
| type: string |
| value: "hello, world" |
| "hello, " mode: value |
| type: untyped string |
| value: "hello, " |
| "world" mode: value |
| type: untyped string |
| value: "world" |
| print(rune(v), ok) mode: void |
| type: () |
| print mode: builtin |
| type: func(rune, bool) |
| rune(v) mode: value |
| type: rune |
| rune mode: type |
| type: rune |
| ...more not shown... |
| //!-output |
| */ |