script_parser.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "go/ast"
  6. "io"
  7. "os"
  8. "path/filepath"
  9. "regexp"
  10. "strings"
  11. "github.com/pkg/errors"
  12. )
  13. var (
  14. _lints = make([]*lint, 0)
  15. )
  16. func walkScript(dir string) {
  17. fn := func(path string, info os.FileInfo, err error) error {
  18. if err != nil {
  19. _log.Debugf("%+v", err)
  20. return err
  21. }
  22. if !strings.HasSuffix(info.Name(), ".bgl") {
  23. return nil
  24. }
  25. var (
  26. file *os.File
  27. newErr error
  28. scripts []*script
  29. )
  30. if file, newErr = os.Open(path); newErr != nil {
  31. newErr = errors.WithStack(newErr)
  32. return newErr
  33. }
  34. if scripts, newErr = fileToScript(file, path); newErr != nil {
  35. newErr = errors.WithStack(newErr)
  36. return newErr
  37. }
  38. for _, s := range scripts {
  39. registerLints(s)
  40. }
  41. return nil
  42. }
  43. if err := filepath.Walk(dir, fn); err != nil {
  44. panic(err)
  45. }
  46. }
  47. func fileToScript(file *os.File, path string) (scripts []*script, err error) {
  48. var (
  49. br = bufio.NewReader(file)
  50. curScript *script
  51. line []byte
  52. isPrefix bool
  53. )
  54. for line, isPrefix, err = br.ReadLine(); err != io.EOF; line, isPrefix, err = br.ReadLine() {
  55. if err != nil {
  56. err = errors.WithStack(err)
  57. return
  58. }
  59. if isPrefix {
  60. _log.Fatalf("parseScript file: %s/%s err: some line too long", path, file.Name())
  61. }
  62. strs := strings.Split(strings.TrimSpace(string(line)), " ")
  63. if len(strs) != 2 {
  64. continue
  65. }
  66. k, v := strs[0], strs[1]
  67. switch k {
  68. case "T":
  69. ts := strings.Split(strings.TrimSpace(v), ".")
  70. curScript = &script{
  71. dir: filepath.Dir(path),
  72. ts: ts,
  73. l: "e",
  74. d: fmt.Sprintf("{%s : %s}", strings.Join(ts, "."), v),
  75. }
  76. case "V":
  77. if curScript != nil {
  78. curScript.v = v
  79. }
  80. scripts = append(scripts, curScript)
  81. case "L":
  82. if curScript != nil {
  83. curScript.l = v
  84. }
  85. case "D":
  86. if curScript != nil {
  87. curScript.d = v
  88. }
  89. }
  90. }
  91. err = nil
  92. return
  93. }
  94. func registerLints(script *script) {
  95. _lints = append(_lints, &lint{
  96. s: script,
  97. fn: assembleLint(script),
  98. })
  99. }
  100. func assembleLint(script *script) func(curDir string, f *ast.File, node ast.Node) bool {
  101. var (
  102. reg *regexp.Regexp
  103. err error
  104. )
  105. _log.Debugf("assembleLint script: %+v", script)
  106. if reg, err = regexp.Compile(script.v); err != nil {
  107. _log.Fatalf("assembleLint script: %s, v compile error: %+v", script, err)
  108. return nil
  109. }
  110. return func(curDir string, f *ast.File, n ast.Node) bool {
  111. // if !strings.HasPrefix(curDir, script.dir) {
  112. // return true
  113. // }
  114. var (
  115. parse func(curDir string, f *ast.File, n ast.Node) (v string, hit bool)
  116. ok bool
  117. k = strings.Join(script.ts, ".")
  118. )
  119. if parse, ok = _parsers[k]; !ok {
  120. return true
  121. }
  122. content, hit := parse(curDir, f, n)
  123. if !hit {
  124. return true
  125. }
  126. return !reg.MatchString(content) // 返回是否是正常node(未命中lint)
  127. }
  128. }