You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

373 lines
8.9 KiB

  1. // Copyright 2014 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. package main
  5. import (
  6. "bytes"
  7. "fmt"
  8. exact "go/constant"
  9. "go/token"
  10. "go/types"
  11. "io"
  12. "math/big"
  13. )
  14. // TODO(gri) use tabwriter for alignment?
  15. func print(w io.Writer, pkg *types.Package, filter func(types.Object) bool) {
  16. var p printer
  17. p.pkg = pkg
  18. p.printPackage(pkg, filter)
  19. p.printGccgoExtra(pkg)
  20. io.Copy(w, &p.buf)
  21. }
  22. type printer struct {
  23. pkg *types.Package
  24. buf bytes.Buffer
  25. indent int // current indentation level
  26. last byte // last byte written
  27. }
  28. func (p *printer) print(s string) {
  29. // Write the string one byte at a time. We care about the presence of
  30. // newlines for indentation which we will see even in the presence of
  31. // (non-corrupted) Unicode; no need to read one rune at a time.
  32. for i := 0; i < len(s); i++ {
  33. ch := s[i]
  34. if ch != '\n' && p.last == '\n' {
  35. // Note: This could lead to a range overflow for very large
  36. // indentations, but it's extremely unlikely to happen for
  37. // non-pathological code.
  38. p.buf.WriteString("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[:p.indent])
  39. }
  40. p.buf.WriteByte(ch)
  41. p.last = ch
  42. }
  43. }
  44. func (p *printer) printf(format string, args ...interface{}) {
  45. p.print(fmt.Sprintf(format, args...))
  46. }
  47. // methodsFor returns the named type and corresponding methods if the type
  48. // denoted by obj is not an interface and has methods. Otherwise it returns
  49. // the zero value.
  50. func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
  51. named, _ := obj.Type().(*types.Named)
  52. if named == nil {
  53. // A type name's type can also be the
  54. // exported basic type unsafe.Pointer.
  55. return nil, nil
  56. }
  57. if _, ok := named.Underlying().(*types.Interface); ok {
  58. // ignore interfaces
  59. return nil, nil
  60. }
  61. methods := combinedMethodSet(named)
  62. if len(methods) == 0 {
  63. return nil, nil
  64. }
  65. return named, methods
  66. }
  67. func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
  68. // collect objects by kind
  69. var (
  70. consts []*types.Const
  71. typem []*types.Named // non-interface types with methods
  72. typez []*types.TypeName // interfaces or types without methods
  73. vars []*types.Var
  74. funcs []*types.Func
  75. builtins []*types.Builtin
  76. methods = make(map[*types.Named][]*types.Selection) // method sets for named types
  77. )
  78. scope := pkg.Scope()
  79. for _, name := range scope.Names() {
  80. obj := scope.Lookup(name)
  81. if obj.Exported() {
  82. // collect top-level exported and possibly filtered objects
  83. if filter == nil || filter(obj) {
  84. switch obj := obj.(type) {
  85. case *types.Const:
  86. consts = append(consts, obj)
  87. case *types.TypeName:
  88. // group into types with methods and types without
  89. if named, m := methodsFor(obj); named != nil {
  90. typem = append(typem, named)
  91. methods[named] = m
  92. } else {
  93. typez = append(typez, obj)
  94. }
  95. case *types.Var:
  96. vars = append(vars, obj)
  97. case *types.Func:
  98. funcs = append(funcs, obj)
  99. case *types.Builtin:
  100. // for unsafe.Sizeof, etc.
  101. builtins = append(builtins, obj)
  102. }
  103. }
  104. } else if filter == nil {
  105. // no filtering: collect top-level unexported types with methods
  106. if obj, _ := obj.(*types.TypeName); obj != nil {
  107. // see case *types.TypeName above
  108. if named, m := methodsFor(obj); named != nil {
  109. typem = append(typem, named)
  110. methods[named] = m
  111. }
  112. }
  113. }
  114. }
  115. p.printf("package %s // %q\n", pkg.Name(), pkg.Path())
  116. p.printDecl("const", len(consts), func() {
  117. for _, obj := range consts {
  118. p.printObj(obj)
  119. p.print("\n")
  120. }
  121. })
  122. p.printDecl("var", len(vars), func() {
  123. for _, obj := range vars {
  124. p.printObj(obj)
  125. p.print("\n")
  126. }
  127. })
  128. p.printDecl("type", len(typez), func() {
  129. for _, obj := range typez {
  130. p.printf("%s ", obj.Name())
  131. typ := obj.Type()
  132. if isAlias(obj) {
  133. p.print("= ")
  134. p.writeType(p.pkg, typ)
  135. } else {
  136. p.writeType(p.pkg, typ.Underlying())
  137. }
  138. p.print("\n")
  139. }
  140. })
  141. // non-interface types with methods
  142. for _, named := range typem {
  143. first := true
  144. if obj := named.Obj(); obj.Exported() {
  145. if first {
  146. p.print("\n")
  147. first = false
  148. }
  149. p.printf("type %s ", obj.Name())
  150. p.writeType(p.pkg, named.Underlying())
  151. p.print("\n")
  152. }
  153. for _, m := range methods[named] {
  154. if obj := m.Obj(); obj.Exported() {
  155. if first {
  156. p.print("\n")
  157. first = false
  158. }
  159. p.printFunc(m.Recv(), obj.(*types.Func))
  160. p.print("\n")
  161. }
  162. }
  163. }
  164. if len(funcs) > 0 {
  165. p.print("\n")
  166. for _, obj := range funcs {
  167. p.printFunc(nil, obj)
  168. p.print("\n")
  169. }
  170. }
  171. // TODO(gri) better handling of builtins (package unsafe only)
  172. if len(builtins) > 0 {
  173. p.print("\n")
  174. for _, obj := range builtins {
  175. p.printf("func %s() // builtin\n", obj.Name())
  176. }
  177. }
  178. p.print("\n")
  179. }
  180. func (p *printer) printDecl(keyword string, n int, printGroup func()) {
  181. switch n {
  182. case 0:
  183. // nothing to do
  184. case 1:
  185. p.printf("\n%s ", keyword)
  186. printGroup()
  187. default:
  188. p.printf("\n%s (\n", keyword)
  189. p.indent++
  190. printGroup()
  191. p.indent--
  192. p.print(")\n")
  193. }
  194. }
  195. // absInt returns the absolute value of v as a *big.Int.
  196. // v must be a numeric value.
  197. func absInt(v exact.Value) *big.Int {
  198. // compute big-endian representation of v
  199. b := exact.Bytes(v) // little-endian
  200. for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
  201. b[i], b[j] = b[j], b[i]
  202. }
  203. return new(big.Int).SetBytes(b)
  204. }
  205. var (
  206. one = big.NewRat(1, 1)
  207. ten = big.NewRat(10, 1)
  208. )
  209. // floatString returns the string representation for a
  210. // numeric value v in normalized floating-point format.
  211. func floatString(v exact.Value) string {
  212. if exact.Sign(v) == 0 {
  213. return "0.0"
  214. }
  215. // x != 0
  216. // convert |v| into a big.Rat x
  217. x := new(big.Rat).SetFrac(absInt(exact.Num(v)), absInt(exact.Denom(v)))
  218. // normalize x and determine exponent e
  219. // (This is not very efficient, but also not speed-critical.)
  220. var e int
  221. for x.Cmp(ten) >= 0 {
  222. x.Quo(x, ten)
  223. e++
  224. }
  225. for x.Cmp(one) < 0 {
  226. x.Mul(x, ten)
  227. e--
  228. }
  229. // TODO(gri) Values such as 1/2 are easier to read in form 0.5
  230. // rather than 5.0e-1. Similarly, 1.0e1 is easier to read as
  231. // 10.0. Fine-tune best exponent range for readability.
  232. s := x.FloatString(100) // good-enough precision
  233. // trim trailing 0's
  234. i := len(s)
  235. for i > 0 && s[i-1] == '0' {
  236. i--
  237. }
  238. s = s[:i]
  239. // add a 0 if the number ends in decimal point
  240. if len(s) > 0 && s[len(s)-1] == '.' {
  241. s += "0"
  242. }
  243. // add exponent and sign
  244. if e != 0 {
  245. s += fmt.Sprintf("e%+d", e)
  246. }
  247. if exact.Sign(v) < 0 {
  248. s = "-" + s
  249. }
  250. // TODO(gri) If v is a "small" fraction (i.e., numerator and denominator
  251. // are just a small number of decimal digits), add the exact fraction as
  252. // a comment. For instance: 3.3333...e-1 /* = 1/3 */
  253. return s
  254. }
  255. // valString returns the string representation for the value v.
  256. // Setting floatFmt forces an integer value to be formatted in
  257. // normalized floating-point format.
  258. // TODO(gri) Move this code into package exact.
  259. func valString(v exact.Value, floatFmt bool) string {
  260. switch v.Kind() {
  261. case exact.Int:
  262. if floatFmt {
  263. return floatString(v)
  264. }
  265. case exact.Float:
  266. return floatString(v)
  267. case exact.Complex:
  268. re := exact.Real(v)
  269. im := exact.Imag(v)
  270. var s string
  271. if exact.Sign(re) != 0 {
  272. s = floatString(re)
  273. if exact.Sign(im) >= 0 {
  274. s += " + "
  275. } else {
  276. s += " - "
  277. im = exact.UnaryOp(token.SUB, im, 0) // negate im
  278. }
  279. }
  280. // im != 0, otherwise v would be exact.Int or exact.Float
  281. return s + floatString(im) + "i"
  282. }
  283. return v.String()
  284. }
  285. func (p *printer) printObj(obj types.Object) {
  286. p.print(obj.Name())
  287. typ, basic := obj.Type().Underlying().(*types.Basic)
  288. if basic && typ.Info()&types.IsUntyped != 0 {
  289. // don't write untyped types
  290. } else {
  291. p.print(" ")
  292. p.writeType(p.pkg, obj.Type())
  293. }
  294. if obj, ok := obj.(*types.Const); ok {
  295. floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0
  296. p.print(" = ")
  297. p.print(valString(obj.Val(), floatFmt))
  298. }
  299. }
  300. func (p *printer) printFunc(recvType types.Type, obj *types.Func) {
  301. p.print("func ")
  302. sig := obj.Type().(*types.Signature)
  303. if recvType != nil {
  304. p.print("(")
  305. p.writeType(p.pkg, recvType)
  306. p.print(") ")
  307. }
  308. p.print(obj.Name())
  309. p.writeSignature(p.pkg, sig)
  310. }
  311. // combinedMethodSet returns the method set for a named type T
  312. // merged with all the methods of *T that have different names than
  313. // the methods of T.
  314. //
  315. // combinedMethodSet is analogous to types/typeutil.IntuitiveMethodSet
  316. // but doesn't require a MethodSetCache.
  317. // TODO(gri) If this functionality doesn't change over time, consider
  318. // just calling IntuitiveMethodSet eventually.
  319. func combinedMethodSet(T *types.Named) []*types.Selection {
  320. // method set for T
  321. mset := types.NewMethodSet(T)
  322. var res []*types.Selection
  323. for i, n := 0, mset.Len(); i < n; i++ {
  324. res = append(res, mset.At(i))
  325. }
  326. // add all *T methods with names different from T methods
  327. pmset := types.NewMethodSet(types.NewPointer(T))
  328. for i, n := 0, pmset.Len(); i < n; i++ {
  329. pm := pmset.At(i)
  330. if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil {
  331. res = append(res, pm)
  332. }
  333. }
  334. return res
  335. }