print.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package ast
  2. import (
  3. "fmt"
  4. "go/token"
  5. "io"
  6. "os"
  7. "reflect"
  8. apitoken "github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/token"
  9. )
  10. // A FieldFilter may be provided to Fprint to control the output.
  11. type FieldFilter func(name string, value reflect.Value) bool
  12. // NotNilFilter returns true for field values that are not nil,
  13. // it returns false otherwise.
  14. func NotNilFilter(_ string, v reflect.Value) bool {
  15. switch v.Kind() {
  16. case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
  17. return !v.IsNil()
  18. }
  19. return true
  20. }
  21. // Fprint prints the value of x to the writer w.
  22. func Fprint(w io.Writer, x interface{}, f FieldFilter) error {
  23. return fprint(w, x, f)
  24. }
  25. func fprint(w io.Writer, x interface{}, f FieldFilter) (err error) {
  26. // setup printer
  27. p := printer{
  28. output: w,
  29. filter: f,
  30. ptrmap: make(map[interface{}]int),
  31. last: '\n', // force printing of line number on first line
  32. }
  33. // install error handler
  34. defer func() {
  35. if e := recover(); e != nil {
  36. err = e.(localError).err // re-panics if it's not a localError
  37. }
  38. }()
  39. // print x
  40. if x == nil {
  41. p.printf("nil\n")
  42. return
  43. }
  44. p.print(reflect.ValueOf(x))
  45. p.printf("\n")
  46. return
  47. }
  48. func Print(x interface{}) error {
  49. return Fprint(os.Stdout, x, NotNilFilter)
  50. }
  51. type printer struct {
  52. output io.Writer
  53. filter FieldFilter
  54. ptrmap map[interface{}]int // *T -> line number
  55. prefixIndent int // current indentation level
  56. last byte // the last byte processed by Write
  57. line int // current line number
  58. }
  59. var prefixIndent = []byte(". ")
  60. // Write implements io.Writer.
  61. func (p *printer) Write(data []byte) (n int, err error) {
  62. var m int
  63. for i, b := range data {
  64. // invariant: data[0:n] has been written
  65. if b == '\n' {
  66. m, err = p.output.Write(data[n : i+1])
  67. n += m
  68. if err != nil {
  69. return
  70. }
  71. p.line++
  72. } else if p.last == '\n' {
  73. _, err = fmt.Fprintf(p.output, "%6d ", p.line)
  74. if err != nil {
  75. return
  76. }
  77. for j := p.prefixIndent; j > 0; j-- {
  78. _, err = p.output.Write(prefixIndent)
  79. if err != nil {
  80. return
  81. }
  82. }
  83. }
  84. p.last = b
  85. }
  86. if len(data) > n {
  87. m, err = p.output.Write(data[n:])
  88. n += m
  89. }
  90. return
  91. }
  92. // localError wraps locally caught errors so we can distinguish
  93. // them from genuine panics which we don't want to return as errors.
  94. type localError struct {
  95. err error
  96. }
  97. // printf is a convenience wrapper that takes care of print errors.
  98. func (p *printer) printf(format string, args ...interface{}) {
  99. if _, err := fmt.Fprintf(p, format, args...); err != nil {
  100. panic(localError{err})
  101. }
  102. }
  103. // Implementation note: Print is written for AST nodes but could be
  104. // used to print arbitrary data structures; such a version should
  105. // probably be in a different package.
  106. //
  107. // Note: This code detects (some) cycles created via pointers but
  108. // not cycles that are created via slices or maps containing the
  109. // same slice or map. Code for general data structures probably
  110. // should catch those as well.
  111. func (p *printer) print(x reflect.Value) {
  112. if !NotNilFilter("", x) {
  113. p.printf("nil")
  114. return
  115. }
  116. switch x.Kind() {
  117. case reflect.Interface:
  118. p.print(x.Elem())
  119. case reflect.Map:
  120. p.printf("%s (len = %d) {", x.Type(), x.Len())
  121. if x.Len() > 0 {
  122. p.prefixIndent++
  123. p.printf("\n")
  124. for _, key := range x.MapKeys() {
  125. p.print(key)
  126. p.printf(": ")
  127. p.print(x.MapIndex(key))
  128. p.printf("\n")
  129. }
  130. p.prefixIndent--
  131. }
  132. p.printf("}")
  133. case reflect.Pointer:
  134. p.printf("*")
  135. // type-checked ASTs may contain cycles - use ptrmap
  136. // to keep track of objects that have been printed
  137. // already and print the respective line number instead
  138. ptr := x.Interface()
  139. if line, exists := p.ptrmap[ptr]; exists {
  140. p.printf("(obj @ %d)", line)
  141. } else {
  142. p.ptrmap[ptr] = p.line
  143. p.print(x.Elem())
  144. }
  145. case reflect.Array:
  146. p.printf("%s {", x.Type())
  147. if x.Len() > 0 {
  148. p.prefixIndent++
  149. p.printf("\n")
  150. for i, n := 0, x.Len(); i < n; i++ {
  151. p.printf("%d: ", i)
  152. p.print(x.Index(i))
  153. p.printf("\n")
  154. }
  155. p.prefixIndent--
  156. }
  157. p.printf("}")
  158. case reflect.Slice:
  159. if s, ok := x.Interface().([]byte); ok {
  160. p.printf("%#q", s)
  161. return
  162. }
  163. p.printf("%s (len = %d) {", x.Type(), x.Len())
  164. if x.Len() > 0 {
  165. p.prefixIndent++
  166. p.printf("\n")
  167. for i, n := 0, x.Len(); i < n; i++ {
  168. p.printf("%d: ", i)
  169. p.print(x.Index(i))
  170. p.printf("\n")
  171. }
  172. p.prefixIndent--
  173. }
  174. p.printf("}")
  175. case reflect.Struct:
  176. if val, ok := x.Interface().(apitoken.Position); ok {
  177. p.printf(val.String())
  178. return
  179. }
  180. t := x.Type()
  181. p.printf("%s {", t)
  182. p.prefixIndent++
  183. first := true
  184. for i, n := 0, t.NumField(); i < n; i++ {
  185. // exclude non-exported fields because their
  186. // values cannot be accessed via reflection
  187. if name := t.Field(i).Name; token.IsExported(name) {
  188. value := x.Field(i)
  189. if p.filter == nil || p.filter(name, value) {
  190. if first {
  191. p.printf("\n")
  192. first = false
  193. }
  194. p.printf("%s: ", name)
  195. p.print(value)
  196. p.printf("\n")
  197. }
  198. }
  199. }
  200. p.prefixIndent--
  201. p.printf("}")
  202. default:
  203. v := x.Interface()
  204. switch v := v.(type) {
  205. case string:
  206. // print strings in quotes
  207. p.printf("%q", v)
  208. return
  209. }
  210. // default
  211. p.printf("%v", v)
  212. }
  213. }