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.

587 lines
12 KiB

  1. package parse
  2. import (
  3. "fmt"
  4. "go/ast"
  5. "go/parser"
  6. "go/token"
  7. "os"
  8. "reflect"
  9. "sort"
  10. "strings"
  11. "github.com/tinylib/msgp/gen"
  12. "github.com/ttacon/chalk"
  13. )
  14. // A FileSet is the in-memory representation of a
  15. // parsed file.
  16. type FileSet struct {
  17. Package string // package name
  18. Specs map[string]ast.Expr // type specs in file
  19. Identities map[string]gen.Elem // processed from specs
  20. Directives []string // raw preprocessor directives
  21. Imports []*ast.ImportSpec // imports
  22. }
  23. // File parses a file at the relative path
  24. // provided and produces a new *FileSet.
  25. // If you pass in a path to a directory, the entire
  26. // directory will be parsed.
  27. // If unexport is false, only exported identifiers are included in the FileSet.
  28. // If the resulting FileSet would be empty, an error is returned.
  29. func File(name string, unexported bool) (*FileSet, error) {
  30. pushstate(name)
  31. defer popstate()
  32. fs := &FileSet{
  33. Specs: make(map[string]ast.Expr),
  34. Identities: make(map[string]gen.Elem),
  35. }
  36. fset := token.NewFileSet()
  37. finfo, err := os.Stat(name)
  38. if err != nil {
  39. return nil, err
  40. }
  41. if finfo.IsDir() {
  42. pkgs, err := parser.ParseDir(fset, name, nil, parser.ParseComments)
  43. if err != nil {
  44. return nil, err
  45. }
  46. if len(pkgs) != 1 {
  47. return nil, fmt.Errorf("multiple packages in directory: %s", name)
  48. }
  49. var one *ast.Package
  50. for _, nm := range pkgs {
  51. one = nm
  52. break
  53. }
  54. fs.Package = one.Name
  55. for _, fl := range one.Files {
  56. pushstate(fl.Name.Name)
  57. fs.Directives = append(fs.Directives, yieldComments(fl.Comments)...)
  58. if !unexported {
  59. ast.FileExports(fl)
  60. }
  61. fs.getTypeSpecs(fl)
  62. popstate()
  63. }
  64. } else {
  65. f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
  66. if err != nil {
  67. return nil, err
  68. }
  69. fs.Package = f.Name.Name
  70. fs.Directives = yieldComments(f.Comments)
  71. if !unexported {
  72. ast.FileExports(f)
  73. }
  74. fs.getTypeSpecs(f)
  75. }
  76. if len(fs.Specs) == 0 {
  77. return nil, fmt.Errorf("no definitions in %s", name)
  78. }
  79. fs.process()
  80. fs.applyDirectives()
  81. fs.propInline()
  82. return fs, nil
  83. }
  84. // applyDirectives applies all of the directives that
  85. // are known to the parser. additional method-specific
  86. // directives remain in f.Directives
  87. func (f *FileSet) applyDirectives() {
  88. newdirs := make([]string, 0, len(f.Directives))
  89. for _, d := range f.Directives {
  90. chunks := strings.Split(d, " ")
  91. if len(chunks) > 0 {
  92. if fn, ok := directives[chunks[0]]; ok {
  93. pushstate(chunks[0])
  94. err := fn(chunks, f)
  95. if err != nil {
  96. warnln(err.Error())
  97. }
  98. popstate()
  99. } else {
  100. newdirs = append(newdirs, d)
  101. }
  102. }
  103. }
  104. f.Directives = newdirs
  105. }
  106. // A linkset is a graph of unresolved
  107. // identities.
  108. //
  109. // Since gen.Ident can only represent
  110. // one level of type indirection (e.g. Foo -> uint8),
  111. // type declarations like `type Foo Bar`
  112. // aren't resolve-able until we've processed
  113. // everything else.
  114. //
  115. // The goal of this dependency resolution
  116. // is to distill the type declaration
  117. // into just one level of indirection.
  118. // In other words, if we have:
  119. //
  120. // type A uint64
  121. // type B A
  122. // type C B
  123. // type D C
  124. //
  125. // ... then we want to end up
  126. // figuring out that D is just a uint64.
  127. type linkset map[string]*gen.BaseElem
  128. func (f *FileSet) resolve(ls linkset) {
  129. progress := true
  130. for progress && len(ls) > 0 {
  131. progress = false
  132. for name, elem := range ls {
  133. real, ok := f.Identities[elem.TypeName()]
  134. if ok {
  135. // copy the old type descriptor,
  136. // alias it to the new value,
  137. // and insert it into the resolved
  138. // identities list
  139. progress = true
  140. nt := real.Copy()
  141. nt.Alias(name)
  142. f.Identities[name] = nt
  143. delete(ls, name)
  144. }
  145. }
  146. }
  147. // what's left can't be resolved
  148. for name, elem := range ls {
  149. warnf("couldn't resolve type %s (%s)\n", name, elem.TypeName())
  150. }
  151. }
  152. // process takes the contents of f.Specs and
  153. // uses them to populate f.Identities
  154. func (f *FileSet) process() {
  155. deferred := make(linkset)
  156. parse:
  157. for name, def := range f.Specs {
  158. pushstate(name)
  159. el := f.parseExpr(def)
  160. if el == nil {
  161. warnln("failed to parse")
  162. popstate()
  163. continue parse
  164. }
  165. // push unresolved identities into
  166. // the graph of links and resolve after
  167. // we've handled every possible named type.
  168. if be, ok := el.(*gen.BaseElem); ok && be.Value == gen.IDENT {
  169. deferred[name] = be
  170. popstate()
  171. continue parse
  172. }
  173. el.Alias(name)
  174. f.Identities[name] = el
  175. popstate()
  176. }
  177. if len(deferred) > 0 {
  178. f.resolve(deferred)
  179. }
  180. }
  181. func strToMethod(s string) gen.Method {
  182. switch s {
  183. case "encode":
  184. return gen.Encode
  185. case "decode":
  186. return gen.Decode
  187. case "test":
  188. return gen.Test
  189. case "size":
  190. return gen.Size
  191. case "marshal":
  192. return gen.Marshal
  193. case "unmarshal":
  194. return gen.Unmarshal
  195. default:
  196. return 0
  197. }
  198. }
  199. func (f *FileSet) applyDirs(p *gen.Printer) {
  200. // apply directives of the form
  201. //
  202. // //msgp:encode ignore {{TypeName}}
  203. //
  204. loop:
  205. for _, d := range f.Directives {
  206. chunks := strings.Split(d, " ")
  207. if len(chunks) > 1 {
  208. for i := range chunks {
  209. chunks[i] = strings.TrimSpace(chunks[i])
  210. }
  211. m := strToMethod(chunks[0])
  212. if m == 0 {
  213. warnf("unknown pass name: %q\n", chunks[0])
  214. continue loop
  215. }
  216. if fn, ok := passDirectives[chunks[1]]; ok {
  217. pushstate(chunks[1])
  218. err := fn(m, chunks[2:], p)
  219. if err != nil {
  220. warnf("error applying directive: %s\n", err)
  221. }
  222. popstate()
  223. } else {
  224. warnf("unrecognized directive %q\n", chunks[1])
  225. }
  226. } else {
  227. warnf("empty directive: %q\n", d)
  228. }
  229. }
  230. }
  231. func (f *FileSet) PrintTo(p *gen.Printer) error {
  232. f.applyDirs(p)
  233. names := make([]string, 0, len(f.Identities))
  234. for name := range f.Identities {
  235. names = append(names, name)
  236. }
  237. sort.Strings(names)
  238. for _, name := range names {
  239. el := f.Identities[name]
  240. el.SetVarname("z")
  241. pushstate(el.TypeName())
  242. err := p.Print(el)
  243. popstate()
  244. if err != nil {
  245. return err
  246. }
  247. }
  248. return nil
  249. }
  250. // getTypeSpecs extracts all of the *ast.TypeSpecs in the file
  251. // into fs.Identities, but does not set the actual element
  252. func (fs *FileSet) getTypeSpecs(f *ast.File) {
  253. // collect all imports...
  254. fs.Imports = append(fs.Imports, f.Imports...)
  255. // check all declarations...
  256. for i := range f.Decls {
  257. // for GenDecls...
  258. if g, ok := f.Decls[i].(*ast.GenDecl); ok {
  259. // and check the specs...
  260. for _, s := range g.Specs {
  261. // for ast.TypeSpecs....
  262. if ts, ok := s.(*ast.TypeSpec); ok {
  263. switch ts.Type.(type) {
  264. // this is the list of parse-able
  265. // type specs
  266. case *ast.StructType,
  267. *ast.ArrayType,
  268. *ast.StarExpr,
  269. *ast.MapType,
  270. *ast.Ident:
  271. fs.Specs[ts.Name.Name] = ts.Type
  272. }
  273. }
  274. }
  275. }
  276. }
  277. }
  278. func fieldName(f *ast.Field) string {
  279. switch len(f.Names) {
  280. case 0:
  281. return stringify(f.Type)
  282. case 1:
  283. return f.Names[0].Name
  284. default:
  285. return f.Names[0].Name + " (and others)"
  286. }
  287. }
  288. func (fs *FileSet) parseFieldList(fl *ast.FieldList) []gen.StructField {
  289. if fl == nil || fl.NumFields() == 0 {
  290. return nil
  291. }
  292. out := make([]gen.StructField, 0, fl.NumFields())
  293. for _, field := range fl.List {
  294. pushstate(fieldName(field))
  295. fds := fs.getField(field)
  296. if len(fds) > 0 {
  297. out = append(out, fds...)
  298. } else {
  299. warnln("ignored.")
  300. }
  301. popstate()
  302. }
  303. return out
  304. }
  305. // translate *ast.Field into []gen.StructField
  306. func (fs *FileSet) getField(f *ast.Field) []gen.StructField {
  307. sf := make([]gen.StructField, 1)
  308. var extension bool
  309. // parse tag; otherwise field name is field tag
  310. if f.Tag != nil {
  311. body := reflect.StructTag(strings.Trim(f.Tag.Value, "`")).Get("msg")
  312. tags := strings.Split(body, ",")
  313. if len(tags) == 2 && tags[1] == "extension" {
  314. extension = true
  315. }
  316. // ignore "-" fields
  317. if tags[0] == "-" {
  318. return nil
  319. }
  320. sf[0].FieldTag = tags[0]
  321. sf[0].RawTag = f.Tag.Value
  322. }
  323. ex := fs.parseExpr(f.Type)
  324. if ex == nil {
  325. return nil
  326. }
  327. // parse field name
  328. switch len(f.Names) {
  329. case 0:
  330. sf[0].FieldName = embedded(f.Type)
  331. case 1:
  332. sf[0].FieldName = f.Names[0].Name
  333. default:
  334. // this is for a multiple in-line declaration,
  335. // e.g. type A struct { One, Two int }
  336. sf = sf[0:0]
  337. for _, nm := range f.Names {
  338. sf = append(sf, gen.StructField{
  339. FieldTag: nm.Name,
  340. FieldName: nm.Name,
  341. FieldElem: ex.Copy(),
  342. })
  343. }
  344. return sf
  345. }
  346. sf[0].FieldElem = ex
  347. if sf[0].FieldTag == "" {
  348. sf[0].FieldTag = sf[0].FieldName
  349. }
  350. // validate extension
  351. if extension {
  352. switch ex := ex.(type) {
  353. case *gen.Ptr:
  354. if b, ok := ex.Value.(*gen.BaseElem); ok {
  355. b.Value = gen.Ext
  356. } else {
  357. warnln("couldn't cast to extension.")
  358. return nil
  359. }
  360. case *gen.BaseElem:
  361. ex.Value = gen.Ext
  362. default:
  363. warnln("couldn't cast to extension.")
  364. return nil
  365. }
  366. }
  367. return sf
  368. }
  369. // extract embedded field name
  370. //
  371. // so, for a struct like
  372. //
  373. // type A struct {
  374. // io.Writer
  375. // }
  376. //
  377. // we want "Writer"
  378. func embedded(f ast.Expr) string {
  379. switch f := f.(type) {
  380. case *ast.Ident:
  381. return f.Name
  382. case *ast.StarExpr:
  383. return embedded(f.X)
  384. case *ast.SelectorExpr:
  385. return f.Sel.Name
  386. default:
  387. // other possibilities are disallowed
  388. return ""
  389. }
  390. }
  391. // stringify a field type name
  392. func stringify(e ast.Expr) string {
  393. switch e := e.(type) {
  394. case *ast.Ident:
  395. return e.Name
  396. case *ast.StarExpr:
  397. return "*" + stringify(e.X)
  398. case *ast.SelectorExpr:
  399. return stringify(e.X) + "." + e.Sel.Name
  400. case *ast.ArrayType:
  401. if e.Len == nil {
  402. return "[]" + stringify(e.Elt)
  403. }
  404. return fmt.Sprintf("[%s]%s", stringify(e.Len), stringify(e.Elt))
  405. case *ast.InterfaceType:
  406. if e.Methods == nil || e.Methods.NumFields() == 0 {
  407. return "interface{}"
  408. }
  409. }
  410. return "<BAD>"
  411. }
  412. // recursively translate ast.Expr to gen.Elem; nil means type not supported
  413. // expected input types:
  414. // - *ast.MapType (map[T]J)
  415. // - *ast.Ident (name)
  416. // - *ast.ArrayType ([(sz)]T)
  417. // - *ast.StarExpr (*T)
  418. // - *ast.StructType (struct {})
  419. // - *ast.SelectorExpr (a.B)
  420. // - *ast.InterfaceType (interface {})
  421. func (fs *FileSet) parseExpr(e ast.Expr) gen.Elem {
  422. switch e := e.(type) {
  423. case *ast.MapType:
  424. if k, ok := e.Key.(*ast.Ident); ok && k.Name == "string" {
  425. if in := fs.parseExpr(e.Value); in != nil {
  426. return &gen.Map{Value: in}
  427. }
  428. }
  429. return nil
  430. case *ast.Ident:
  431. b := gen.Ident(e.Name)
  432. // work to resove this expression
  433. // can be done later, once we've resolved
  434. // everything else.
  435. if b.Value == gen.IDENT {
  436. if _, ok := fs.Specs[e.Name]; !ok {
  437. warnf("non-local identifier: %s\n", e.Name)
  438. }
  439. }
  440. return b
  441. case *ast.ArrayType:
  442. // special case for []byte
  443. if e.Len == nil {
  444. if i, ok := e.Elt.(*ast.Ident); ok && i.Name == "byte" {
  445. return &gen.BaseElem{Value: gen.Bytes}
  446. }
  447. }
  448. // return early if we don't know
  449. // what the slice element type is
  450. els := fs.parseExpr(e.Elt)
  451. if els == nil {
  452. return nil
  453. }
  454. // array and not a slice
  455. if e.Len != nil {
  456. switch s := e.Len.(type) {
  457. case *ast.BasicLit:
  458. return &gen.Array{
  459. Size: s.Value,
  460. Els: els,
  461. }
  462. case *ast.Ident:
  463. return &gen.Array{
  464. Size: s.String(),
  465. Els: els,
  466. }
  467. case *ast.SelectorExpr:
  468. return &gen.Array{
  469. Size: stringify(s),
  470. Els: els,
  471. }
  472. default:
  473. return nil
  474. }
  475. }
  476. return &gen.Slice{Els: els}
  477. case *ast.StarExpr:
  478. if v := fs.parseExpr(e.X); v != nil {
  479. return &gen.Ptr{Value: v}
  480. }
  481. return nil
  482. case *ast.StructType:
  483. return &gen.Struct{Fields: fs.parseFieldList(e.Fields)}
  484. case *ast.SelectorExpr:
  485. return gen.Ident(stringify(e))
  486. case *ast.InterfaceType:
  487. // support `interface{}`
  488. if len(e.Methods.List) == 0 {
  489. return &gen.BaseElem{Value: gen.Intf}
  490. }
  491. return nil
  492. default: // other types not supported
  493. return nil
  494. }
  495. }
  496. func infof(s string, v ...interface{}) {
  497. pushstate(s)
  498. fmt.Printf(chalk.Green.Color(strings.Join(logctx, ": ")), v...)
  499. popstate()
  500. }
  501. func infoln(s string) {
  502. pushstate(s)
  503. fmt.Println(chalk.Green.Color(strings.Join(logctx, ": ")))
  504. popstate()
  505. }
  506. func warnf(s string, v ...interface{}) {
  507. pushstate(s)
  508. fmt.Printf(chalk.Yellow.Color(strings.Join(logctx, ": ")), v...)
  509. popstate()
  510. }
  511. func warnln(s string) {
  512. pushstate(s)
  513. fmt.Println(chalk.Yellow.Color(strings.Join(logctx, ": ")))
  514. popstate()
  515. }
  516. func fatalf(s string, v ...interface{}) {
  517. pushstate(s)
  518. fmt.Printf(chalk.Red.Color(strings.Join(logctx, ": ")), v...)
  519. popstate()
  520. }
  521. var logctx []string
  522. // push logging state
  523. func pushstate(s string) {
  524. logctx = append(logctx, s)
  525. }
  526. // pop logging state
  527. func popstate() {
  528. logctx = logctx[:len(logctx)-1]
  529. }