x/tools/cmd/godex: prepare sources for switch to 1.5 go/types
- copied all affected xxx.go files to a respective xxx14.go file - added build tags - no other source changes Change-Id: Ic150a097e537ee29a0e0616ab8e1e74b21e3066d Reviewed-on: https://go-review.googlesource.com/15702 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
13be4dfe75
commit
fe3445e822
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
// This file implements access to gc-generated export data.
|
// This file implements access to gc-generated export data.
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
// This file implements access to gc-generated export data.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/tools/go/gcimporter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
register("gc", gcimporter.Import)
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
// This file implements access to gccgo-generated export data.
|
// This file implements access to gccgo-generated export data.
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
// This file implements access to gccgo-generated export data.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/tools/go/gccgoimporter"
|
||||||
|
"golang.org/x/tools/go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
initmap = make(map[*types.Package]gccgoimporter.InitData)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
incpaths := []string{"/"}
|
||||||
|
|
||||||
|
// importer for default gccgo
|
||||||
|
var inst gccgoimporter.GccgoInstallation
|
||||||
|
inst.InitFromDriver("gccgo")
|
||||||
|
register("gccgo", inst.GetImporter(incpaths, initmap))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the extra gccgo compiler data for this package, if it exists.
|
||||||
|
func (p *printer) printGccgoExtra(pkg *types.Package) {
|
||||||
|
if initdata, ok := initmap[pkg]; ok {
|
||||||
|
p.printf("/*\npriority %d\n", initdata.Priority)
|
||||||
|
|
||||||
|
p.printDecl("init", len(initdata.Inits), func() {
|
||||||
|
for _, init := range initdata.Inits {
|
||||||
|
p.printf("%s %s %d\n", init.Name, init.InitFunc, init.Priority)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
p.print("*/\n")
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/build"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
source = flag.String("s", "", "only consider packages from src, where src is one of the supported compilers")
|
||||||
|
verbose = flag.Bool("v", false, "verbose mode")
|
||||||
|
)
|
||||||
|
|
||||||
|
// lists of registered sources and corresponding importers
|
||||||
|
var (
|
||||||
|
sources []string
|
||||||
|
importers []types.Importer
|
||||||
|
importFailed = errors.New("import failed")
|
||||||
|
)
|
||||||
|
|
||||||
|
// map of imported packages
|
||||||
|
var packages = make(map[string]*types.Package)
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Fprintln(os.Stderr, "usage: godex [flags] {path|qualifiedIdent}")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func report(msg string) {
|
||||||
|
fmt.Fprintln(os.Stderr, "error: "+msg)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if flag.NArg() == 0 {
|
||||||
|
report("no package name, path, or file provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
imp := tryImports
|
||||||
|
if *source != "" {
|
||||||
|
imp = lookup(*source)
|
||||||
|
if imp == nil {
|
||||||
|
report("source (-s argument) must be one of: " + strings.Join(sources, ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range flag.Args() {
|
||||||
|
path, name := splitPathIdent(arg)
|
||||||
|
logf("\tprocessing %q: path = %q, name = %s\n", arg, path, name)
|
||||||
|
|
||||||
|
// generate possible package path prefixes
|
||||||
|
// (at the moment we do this for each argument - should probably cache the generated prefixes)
|
||||||
|
prefixes := make(chan string)
|
||||||
|
go genPrefixes(prefixes, !filepath.IsAbs(path) && !build.IsLocalImport(path))
|
||||||
|
|
||||||
|
// import package
|
||||||
|
pkg, err := tryPrefixes(packages, prefixes, path, imp)
|
||||||
|
if err != nil {
|
||||||
|
logf("\t=> ignoring %q: %s\n", path, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter objects if needed
|
||||||
|
var filter func(types.Object) bool
|
||||||
|
if name != "" {
|
||||||
|
filter = func(obj types.Object) bool {
|
||||||
|
// TODO(gri) perhaps use regular expression matching here?
|
||||||
|
return obj.Name() == name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print contents
|
||||||
|
print(os.Stdout, pkg, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logf(format string, args ...interface{}) {
|
||||||
|
if *verbose {
|
||||||
|
fmt.Fprintf(os.Stderr, format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitPathIdent splits a path.name argument into its components.
|
||||||
|
// All but the last path element may contain dots.
|
||||||
|
func splitPathIdent(arg string) (path, name string) {
|
||||||
|
if i := strings.LastIndex(arg, "."); i >= 0 {
|
||||||
|
if j := strings.LastIndex(arg, "/"); j < i {
|
||||||
|
// '.' is not part of path
|
||||||
|
path = arg[:i]
|
||||||
|
name = arg[i+1:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path = arg
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryPrefixes tries to import the package given by (the possibly partial) path using the given importer imp
|
||||||
|
// by prepending all possible prefixes to path. It returns with the first package that it could import, or
|
||||||
|
// with an error.
|
||||||
|
func tryPrefixes(packages map[string]*types.Package, prefixes chan string, path string, imp types.Importer) (pkg *types.Package, err error) {
|
||||||
|
for prefix := range prefixes {
|
||||||
|
actual := path
|
||||||
|
if prefix == "" {
|
||||||
|
// don't use filepath.Join as it will sanitize the path and remove
|
||||||
|
// a leading dot and then the path is not recognized as a relative
|
||||||
|
// package path by the importers anymore
|
||||||
|
logf("\ttrying no prefix\n")
|
||||||
|
} else {
|
||||||
|
actual = filepath.Join(prefix, path)
|
||||||
|
logf("\ttrying prefix %q\n", prefix)
|
||||||
|
}
|
||||||
|
pkg, err = imp(packages, actual)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
logf("\t=> importing %q failed: %s\n", actual, err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryImports is an importer that tries all registered importers
|
||||||
|
// successively until one of them succeeds or all of them failed.
|
||||||
|
func tryImports(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
|
||||||
|
for i, imp := range importers {
|
||||||
|
logf("\t\ttrying %s import\n", sources[i])
|
||||||
|
pkg, err = imp(packages, path)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
logf("\t\t=> %s import failed: %s\n", sources[i], err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// protect protects an importer imp from panics and returns the protected importer.
|
||||||
|
func protect(imp types.Importer) types.Importer {
|
||||||
|
return func(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
|
||||||
|
defer func() {
|
||||||
|
if recover() != nil {
|
||||||
|
pkg = nil
|
||||||
|
err = importFailed
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return imp(packages, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// register registers an importer imp for a given source src.
|
||||||
|
func register(src string, imp types.Importer) {
|
||||||
|
if lookup(src) != nil {
|
||||||
|
panic(src + " importer already registered")
|
||||||
|
}
|
||||||
|
sources = append(sources, src)
|
||||||
|
importers = append(importers, protect(imp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup returns the importer imp for a given source src.
|
||||||
|
func lookup(src string) types.Importer {
|
||||||
|
for i, s := range sources {
|
||||||
|
if s == src {
|
||||||
|
return importers[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func genPrefixes(out chan string, all bool) {
|
||||||
|
out <- ""
|
||||||
|
if all {
|
||||||
|
platform := build.Default.GOOS + "_" + build.Default.GOARCH
|
||||||
|
dirnames := append([]string{build.Default.GOROOT}, filepath.SplitList(build.Default.GOPATH)...)
|
||||||
|
for _, dirname := range dirnames {
|
||||||
|
walkDir(filepath.Join(dirname, "pkg", platform), "", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func walkDir(dirname, prefix string, out chan string) {
|
||||||
|
fiList, err := ioutil.ReadDir(dirname)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, fi := range fiList {
|
||||||
|
if fi.IsDir() && !strings.HasPrefix(fi.Name(), ".") {
|
||||||
|
prefix := filepath.Join(prefix, fi.Name())
|
||||||
|
out <- prefix
|
||||||
|
walkDir(filepath.Join(dirname, fi.Name()), prefix, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -0,0 +1,370 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"go/token"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/exact"
|
||||||
|
"golang.org/x/tools/go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(gri) use tabwriter for alignment?
|
||||||
|
|
||||||
|
func print(w io.Writer, pkg *types.Package, filter func(types.Object) bool) {
|
||||||
|
var p printer
|
||||||
|
p.pkg = pkg
|
||||||
|
p.printPackage(pkg, filter)
|
||||||
|
p.printGccgoExtra(pkg)
|
||||||
|
io.Copy(w, &p.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
type printer struct {
|
||||||
|
pkg *types.Package
|
||||||
|
buf bytes.Buffer
|
||||||
|
indent int // current indentation level
|
||||||
|
last byte // last byte written
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) print(s string) {
|
||||||
|
// Write the string one byte at a time. We care about the presence of
|
||||||
|
// newlines for indentation which we will see even in the presence of
|
||||||
|
// (non-corrupted) Unicode; no need to read one rune at a time.
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
ch := s[i]
|
||||||
|
if ch != '\n' && p.last == '\n' {
|
||||||
|
// Note: This could lead to a range overflow for very large
|
||||||
|
// indentations, but it's extremely unlikely to happen for
|
||||||
|
// non-pathological code.
|
||||||
|
p.buf.WriteString("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[:p.indent])
|
||||||
|
}
|
||||||
|
p.buf.WriteByte(ch)
|
||||||
|
p.last = ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) printf(format string, args ...interface{}) {
|
||||||
|
p.print(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// methodsFor returns the named type and corresponding methods if the type
|
||||||
|
// denoted by obj is not an interface and has methods. Otherwise it returns
|
||||||
|
// the zero value.
|
||||||
|
func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
|
||||||
|
named, _ := obj.Type().(*types.Named)
|
||||||
|
if named == nil {
|
||||||
|
// A type name's type can also be the
|
||||||
|
// exported basic type unsafe.Pointer.
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if _, ok := named.Underlying().(*types.Interface); ok {
|
||||||
|
// ignore interfaces
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
methods := combinedMethodSet(named)
|
||||||
|
if len(methods) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return named, methods
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
|
||||||
|
// collect objects by kind
|
||||||
|
var (
|
||||||
|
consts []*types.Const
|
||||||
|
typem []*types.Named // non-interface types with methods
|
||||||
|
typez []*types.TypeName // interfaces or types without methods
|
||||||
|
vars []*types.Var
|
||||||
|
funcs []*types.Func
|
||||||
|
builtins []*types.Builtin
|
||||||
|
methods = make(map[*types.Named][]*types.Selection) // method sets for named types
|
||||||
|
)
|
||||||
|
scope := pkg.Scope()
|
||||||
|
for _, name := range scope.Names() {
|
||||||
|
obj := scope.Lookup(name)
|
||||||
|
if obj.Exported() {
|
||||||
|
// collect top-level exported and possibly filtered objects
|
||||||
|
if filter == nil || filter(obj) {
|
||||||
|
switch obj := obj.(type) {
|
||||||
|
case *types.Const:
|
||||||
|
consts = append(consts, obj)
|
||||||
|
case *types.TypeName:
|
||||||
|
// group into types with methods and types without
|
||||||
|
if named, m := methodsFor(obj); named != nil {
|
||||||
|
typem = append(typem, named)
|
||||||
|
methods[named] = m
|
||||||
|
} else {
|
||||||
|
typez = append(typez, obj)
|
||||||
|
}
|
||||||
|
case *types.Var:
|
||||||
|
vars = append(vars, obj)
|
||||||
|
case *types.Func:
|
||||||
|
funcs = append(funcs, obj)
|
||||||
|
case *types.Builtin:
|
||||||
|
// for unsafe.Sizeof, etc.
|
||||||
|
builtins = append(builtins, obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if filter == nil {
|
||||||
|
// no filtering: collect top-level unexported types with methods
|
||||||
|
if obj, _ := obj.(*types.TypeName); obj != nil {
|
||||||
|
// see case *types.TypeName above
|
||||||
|
if named, m := methodsFor(obj); named != nil {
|
||||||
|
typem = append(typem, named)
|
||||||
|
methods[named] = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.printf("package %s // %q\n", pkg.Name(), pkg.Path())
|
||||||
|
|
||||||
|
p.printDecl("const", len(consts), func() {
|
||||||
|
for _, obj := range consts {
|
||||||
|
p.printObj(obj)
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
p.printDecl("var", len(vars), func() {
|
||||||
|
for _, obj := range vars {
|
||||||
|
p.printObj(obj)
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
p.printDecl("type", len(typez), func() {
|
||||||
|
for _, obj := range typez {
|
||||||
|
p.printf("%s ", obj.Name())
|
||||||
|
p.writeType(p.pkg, obj.Type().Underlying())
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// non-interface types with methods
|
||||||
|
for _, named := range typem {
|
||||||
|
first := true
|
||||||
|
if obj := named.Obj(); obj.Exported() {
|
||||||
|
if first {
|
||||||
|
p.print("\n")
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
p.printf("type %s ", obj.Name())
|
||||||
|
p.writeType(p.pkg, named.Underlying())
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
for _, m := range methods[named] {
|
||||||
|
if obj := m.Obj(); obj.Exported() {
|
||||||
|
if first {
|
||||||
|
p.print("\n")
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
p.printFunc(m.Recv(), obj.(*types.Func))
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(funcs) > 0 {
|
||||||
|
p.print("\n")
|
||||||
|
for _, obj := range funcs {
|
||||||
|
p.printFunc(nil, obj)
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(gri) better handling of builtins (package unsafe only)
|
||||||
|
if len(builtins) > 0 {
|
||||||
|
p.print("\n")
|
||||||
|
for _, obj := range builtins {
|
||||||
|
p.printf("func %s() // builtin\n", obj.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) printDecl(keyword string, n int, printGroup func()) {
|
||||||
|
switch n {
|
||||||
|
case 0:
|
||||||
|
// nothing to do
|
||||||
|
case 1:
|
||||||
|
p.printf("\n%s ", keyword)
|
||||||
|
printGroup()
|
||||||
|
default:
|
||||||
|
p.printf("\n%s (\n", keyword)
|
||||||
|
p.indent++
|
||||||
|
printGroup()
|
||||||
|
p.indent--
|
||||||
|
p.print(")\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// absInt returns the absolute value of v as a *big.Int.
|
||||||
|
// v must be a numeric value.
|
||||||
|
func absInt(v exact.Value) *big.Int {
|
||||||
|
// compute big-endian representation of v
|
||||||
|
b := exact.Bytes(v) // little-endian
|
||||||
|
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
b[i], b[j] = b[j], b[i]
|
||||||
|
}
|
||||||
|
return new(big.Int).SetBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
one = big.NewRat(1, 1)
|
||||||
|
ten = big.NewRat(10, 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
// floatString returns the string representation for a
|
||||||
|
// numeric value v in normalized floating-point format.
|
||||||
|
func floatString(v exact.Value) string {
|
||||||
|
if exact.Sign(v) == 0 {
|
||||||
|
return "0.0"
|
||||||
|
}
|
||||||
|
// x != 0
|
||||||
|
|
||||||
|
// convert |v| into a big.Rat x
|
||||||
|
x := new(big.Rat).SetFrac(absInt(exact.Num(v)), absInt(exact.Denom(v)))
|
||||||
|
|
||||||
|
// normalize x and determine exponent e
|
||||||
|
// (This is not very efficient, but also not speed-critical.)
|
||||||
|
var e int
|
||||||
|
for x.Cmp(ten) >= 0 {
|
||||||
|
x.Quo(x, ten)
|
||||||
|
e++
|
||||||
|
}
|
||||||
|
for x.Cmp(one) < 0 {
|
||||||
|
x.Mul(x, ten)
|
||||||
|
e--
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(gri) Values such as 1/2 are easier to read in form 0.5
|
||||||
|
// rather than 5.0e-1. Similarly, 1.0e1 is easier to read as
|
||||||
|
// 10.0. Fine-tune best exponent range for readability.
|
||||||
|
|
||||||
|
s := x.FloatString(100) // good-enough precision
|
||||||
|
|
||||||
|
// trim trailing 0's
|
||||||
|
i := len(s)
|
||||||
|
for i > 0 && s[i-1] == '0' {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
s = s[:i]
|
||||||
|
|
||||||
|
// add a 0 if the number ends in decimal point
|
||||||
|
if len(s) > 0 && s[len(s)-1] == '.' {
|
||||||
|
s += "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// add exponent and sign
|
||||||
|
if e != 0 {
|
||||||
|
s += fmt.Sprintf("e%+d", e)
|
||||||
|
}
|
||||||
|
if exact.Sign(v) < 0 {
|
||||||
|
s = "-" + s
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(gri) If v is a "small" fraction (i.e., numerator and denominator
|
||||||
|
// are just a small number of decimal digits), add the exact fraction as
|
||||||
|
// a comment. For instance: 3.3333...e-1 /* = 1/3 */
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// valString returns the string representation for the value v.
|
||||||
|
// Setting floatFmt forces an integer value to be formatted in
|
||||||
|
// normalized floating-point format.
|
||||||
|
// TODO(gri) Move this code into package exact.
|
||||||
|
func valString(v exact.Value, floatFmt bool) string {
|
||||||
|
switch v.Kind() {
|
||||||
|
case exact.Int:
|
||||||
|
if floatFmt {
|
||||||
|
return floatString(v)
|
||||||
|
}
|
||||||
|
case exact.Float:
|
||||||
|
return floatString(v)
|
||||||
|
case exact.Complex:
|
||||||
|
re := exact.Real(v)
|
||||||
|
im := exact.Imag(v)
|
||||||
|
var s string
|
||||||
|
if exact.Sign(re) != 0 {
|
||||||
|
s = floatString(re)
|
||||||
|
if exact.Sign(im) >= 0 {
|
||||||
|
s += " + "
|
||||||
|
} else {
|
||||||
|
s += " - "
|
||||||
|
im = exact.UnaryOp(token.SUB, im, 0) // negate im
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// im != 0, otherwise v would be exact.Int or exact.Float
|
||||||
|
return s + floatString(im) + "i"
|
||||||
|
}
|
||||||
|
return v.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) printObj(obj types.Object) {
|
||||||
|
p.print(obj.Name())
|
||||||
|
|
||||||
|
typ, basic := obj.Type().Underlying().(*types.Basic)
|
||||||
|
if basic && typ.Info()&types.IsUntyped != 0 {
|
||||||
|
// don't write untyped types
|
||||||
|
} else {
|
||||||
|
p.print(" ")
|
||||||
|
p.writeType(p.pkg, obj.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj, ok := obj.(*types.Const); ok {
|
||||||
|
floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0
|
||||||
|
p.print(" = ")
|
||||||
|
p.print(valString(obj.Val(), floatFmt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) printFunc(recvType types.Type, obj *types.Func) {
|
||||||
|
p.print("func ")
|
||||||
|
sig := obj.Type().(*types.Signature)
|
||||||
|
if recvType != nil {
|
||||||
|
p.print("(")
|
||||||
|
p.writeType(p.pkg, recvType)
|
||||||
|
p.print(") ")
|
||||||
|
}
|
||||||
|
p.print(obj.Name())
|
||||||
|
p.writeSignature(p.pkg, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// combinedMethodSet returns the method set for a named type T
|
||||||
|
// merged with all the methods of *T that have different names than
|
||||||
|
// the methods of T.
|
||||||
|
//
|
||||||
|
// combinedMethodSet is analogous to types/typeutil.IntuitiveMethodSet
|
||||||
|
// but doesn't require a MethodSetCache.
|
||||||
|
// TODO(gri) If this functionality doesn't change over time, consider
|
||||||
|
// just calling IntuitiveMethodSet eventually.
|
||||||
|
func combinedMethodSet(T *types.Named) []*types.Selection {
|
||||||
|
// method set for T
|
||||||
|
mset := types.NewMethodSet(T)
|
||||||
|
var res []*types.Selection
|
||||||
|
for i, n := 0, mset.Len(); i < n; i++ {
|
||||||
|
res = append(res, mset.At(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all *T methods with names different from T methods
|
||||||
|
pmset := types.NewMethodSet(types.NewPointer(T))
|
||||||
|
for i, n := 0, pmset.Len(); i < n; i++ {
|
||||||
|
pm := pmset.At(i)
|
||||||
|
if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil {
|
||||||
|
res = append(res, pm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
// This file implements access to export data from source.
|
// This file implements access to export data from source.
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
// This file implements access to export data from source.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/tools/go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
register("source", sourceImporter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sourceImporter(packages map[string]*types.Package, path string) (*types.Package, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
// This file implements writing of types. The functionality is lifted
|
// This file implements writing of types. The functionality is lifted
|
||||||
// directly from go/types, but now contains various modifications for
|
// directly from go/types, but now contains various modifications for
|
||||||
// nicer output.
|
// nicer output.
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
// This file implements writing of types. The functionality is lifted
|
||||||
|
// directly from go/types, but now contains various modifications for
|
||||||
|
// nicer output.
|
||||||
|
//
|
||||||
|
// TODO(gri) back-port once we have a fixed interface and once the
|
||||||
|
// go/types API is not frozen anymore for the 1.3 release; and remove
|
||||||
|
// this implementation if possible.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "golang.org/x/tools/go/types"
|
||||||
|
|
||||||
|
func (p *printer) writeType(this *types.Package, typ types.Type) {
|
||||||
|
p.writeTypeInternal(this, typ, make([]types.Type, 8))
|
||||||
|
}
|
||||||
|
|
||||||
|
// From go/types - leave for now to ease back-porting this code.
|
||||||
|
const GcCompatibilityMode = false
|
||||||
|
|
||||||
|
func (p *printer) writeTypeInternal(this *types.Package, typ types.Type, visited []types.Type) {
|
||||||
|
// Theoretically, this is a quadratic lookup algorithm, but in
|
||||||
|
// practice deeply nested composite types with unnamed component
|
||||||
|
// types are uncommon. This code is likely more efficient than
|
||||||
|
// using a map.
|
||||||
|
for _, t := range visited {
|
||||||
|
if t == typ {
|
||||||
|
p.printf("○%T", typ) // cycle to typ
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visited = append(visited, typ)
|
||||||
|
|
||||||
|
switch t := typ.(type) {
|
||||||
|
case nil:
|
||||||
|
p.print("<nil>")
|
||||||
|
|
||||||
|
case *types.Basic:
|
||||||
|
if t.Kind() == types.UnsafePointer {
|
||||||
|
p.print("unsafe.")
|
||||||
|
}
|
||||||
|
if GcCompatibilityMode {
|
||||||
|
// forget the alias names
|
||||||
|
switch t.Kind() {
|
||||||
|
case types.Byte:
|
||||||
|
t = types.Typ[types.Uint8]
|
||||||
|
case types.Rune:
|
||||||
|
t = types.Typ[types.Int32]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.print(t.Name())
|
||||||
|
|
||||||
|
case *types.Array:
|
||||||
|
p.printf("[%d]", t.Len())
|
||||||
|
p.writeTypeInternal(this, t.Elem(), visited)
|
||||||
|
|
||||||
|
case *types.Slice:
|
||||||
|
p.print("[]")
|
||||||
|
p.writeTypeInternal(this, t.Elem(), visited)
|
||||||
|
|
||||||
|
case *types.Struct:
|
||||||
|
n := t.NumFields()
|
||||||
|
if n == 0 {
|
||||||
|
p.print("struct{}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.print("struct {\n")
|
||||||
|
p.indent++
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
f := t.Field(i)
|
||||||
|
if !f.Anonymous() {
|
||||||
|
p.printf("%s ", f.Name())
|
||||||
|
}
|
||||||
|
p.writeTypeInternal(this, f.Type(), visited)
|
||||||
|
if tag := t.Tag(i); tag != "" {
|
||||||
|
p.printf(" %q", tag)
|
||||||
|
}
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
p.indent--
|
||||||
|
p.print("}")
|
||||||
|
|
||||||
|
case *types.Pointer:
|
||||||
|
p.print("*")
|
||||||
|
p.writeTypeInternal(this, t.Elem(), visited)
|
||||||
|
|
||||||
|
case *types.Tuple:
|
||||||
|
p.writeTuple(this, t, false, visited)
|
||||||
|
|
||||||
|
case *types.Signature:
|
||||||
|
p.print("func")
|
||||||
|
p.writeSignatureInternal(this, t, visited)
|
||||||
|
|
||||||
|
case *types.Interface:
|
||||||
|
// We write the source-level methods and embedded types rather
|
||||||
|
// than the actual method set since resolved method signatures
|
||||||
|
// may have non-printable cycles if parameters have anonymous
|
||||||
|
// interface types that (directly or indirectly) embed the
|
||||||
|
// current interface. For instance, consider the result type
|
||||||
|
// of m:
|
||||||
|
//
|
||||||
|
// type T interface{
|
||||||
|
// m() interface{ T }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
n := t.NumMethods()
|
||||||
|
if n == 0 {
|
||||||
|
p.print("interface{}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.print("interface {\n")
|
||||||
|
p.indent++
|
||||||
|
if GcCompatibilityMode {
|
||||||
|
// print flattened interface
|
||||||
|
// (useful to compare against gc-generated interfaces)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
m := t.Method(i)
|
||||||
|
p.print(m.Name())
|
||||||
|
p.writeSignatureInternal(this, m.Type().(*types.Signature), visited)
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// print explicit interface methods and embedded types
|
||||||
|
for i, n := 0, t.NumExplicitMethods(); i < n; i++ {
|
||||||
|
m := t.ExplicitMethod(i)
|
||||||
|
p.print(m.Name())
|
||||||
|
p.writeSignatureInternal(this, m.Type().(*types.Signature), visited)
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
for i, n := 0, t.NumEmbeddeds(); i < n; i++ {
|
||||||
|
typ := t.Embedded(i)
|
||||||
|
p.writeTypeInternal(this, typ, visited)
|
||||||
|
p.print("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.indent--
|
||||||
|
p.print("}")
|
||||||
|
|
||||||
|
case *types.Map:
|
||||||
|
p.print("map[")
|
||||||
|
p.writeTypeInternal(this, t.Key(), visited)
|
||||||
|
p.print("]")
|
||||||
|
p.writeTypeInternal(this, t.Elem(), visited)
|
||||||
|
|
||||||
|
case *types.Chan:
|
||||||
|
var s string
|
||||||
|
var parens bool
|
||||||
|
switch t.Dir() {
|
||||||
|
case types.SendRecv:
|
||||||
|
s = "chan "
|
||||||
|
// chan (<-chan T) requires parentheses
|
||||||
|
if c, _ := t.Elem().(*types.Chan); c != nil && c.Dir() == types.RecvOnly {
|
||||||
|
parens = true
|
||||||
|
}
|
||||||
|
case types.SendOnly:
|
||||||
|
s = "chan<- "
|
||||||
|
case types.RecvOnly:
|
||||||
|
s = "<-chan "
|
||||||
|
default:
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
p.print(s)
|
||||||
|
if parens {
|
||||||
|
p.print("(")
|
||||||
|
}
|
||||||
|
p.writeTypeInternal(this, t.Elem(), visited)
|
||||||
|
if parens {
|
||||||
|
p.print(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
case *types.Named:
|
||||||
|
s := "<Named w/o object>"
|
||||||
|
if obj := t.Obj(); obj != nil {
|
||||||
|
if pkg := obj.Pkg(); pkg != nil {
|
||||||
|
if pkg != this {
|
||||||
|
p.print(pkg.Path())
|
||||||
|
p.print(".")
|
||||||
|
}
|
||||||
|
// TODO(gri): function-local named types should be displayed
|
||||||
|
// differently from named types at package level to avoid
|
||||||
|
// ambiguity.
|
||||||
|
}
|
||||||
|
s = obj.Name()
|
||||||
|
}
|
||||||
|
p.print(s)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// For externally defined implementations of Type.
|
||||||
|
p.print(t.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) writeTuple(this *types.Package, tup *types.Tuple, variadic bool, visited []types.Type) {
|
||||||
|
p.print("(")
|
||||||
|
for i, n := 0, tup.Len(); i < n; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
p.print(", ")
|
||||||
|
}
|
||||||
|
v := tup.At(i)
|
||||||
|
if name := v.Name(); name != "" {
|
||||||
|
p.print(name)
|
||||||
|
p.print(" ")
|
||||||
|
}
|
||||||
|
typ := v.Type()
|
||||||
|
if variadic && i == n-1 {
|
||||||
|
p.print("...")
|
||||||
|
typ = typ.(*types.Slice).Elem()
|
||||||
|
}
|
||||||
|
p.writeTypeInternal(this, typ, visited)
|
||||||
|
}
|
||||||
|
p.print(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) writeSignature(this *types.Package, sig *types.Signature) {
|
||||||
|
p.writeSignatureInternal(this, sig, make([]types.Type, 8))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *printer) writeSignatureInternal(this *types.Package, sig *types.Signature, visited []types.Type) {
|
||||||
|
p.writeTuple(this, sig.Params(), sig.Variadic(), visited)
|
||||||
|
|
||||||
|
res := sig.Results()
|
||||||
|
n := res.Len()
|
||||||
|
if n == 0 {
|
||||||
|
// no result
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.print(" ")
|
||||||
|
if n == 1 && res.At(0).Name() == "" {
|
||||||
|
// single unnamed result
|
||||||
|
p.writeTypeInternal(this, res.At(0).Type(), visited)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiple or named result(s)
|
||||||
|
p.writeTuple(this, res, false, visited)
|
||||||
|
}
|
Loading…
Reference in New Issue