baseparser.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package api
  2. import (
  3. "fmt"
  4. "net/http"
  5. "regexp"
  6. "strings"
  7. "unicode"
  8. "github.com/zeromicro/antlr"
  9. )
  10. const (
  11. versionRegex = `(?m)"v[1-9][0-9]*"`
  12. importValueRegex = `(?m)"(/?[a-zA-Z0-9_#-])+\.api"`
  13. tagRegex = `(?m)\x60[a-z]+:".+"\x60`
  14. )
  15. var (
  16. holder = struct{}{}
  17. kind = map[string]struct{}{
  18. "bool": holder,
  19. "int": holder,
  20. "int8": holder,
  21. "int16": holder,
  22. "int32": holder,
  23. "int64": holder,
  24. "uint": holder,
  25. "uint8": holder,
  26. "uint16": holder,
  27. "uint32": holder,
  28. "uint64": holder,
  29. "uintptr": holder,
  30. "float32": holder,
  31. "float64": holder,
  32. "complex64": holder,
  33. "complex128": holder,
  34. "string": holder,
  35. "byte": holder,
  36. "rune": holder,
  37. }
  38. )
  39. func match(p *ApiParserParser, text string) {
  40. v := getCurrentTokenText(p)
  41. if v != text {
  42. notifyErrorListeners(p, expecting(text, v))
  43. }
  44. }
  45. func checkVersion(p *ApiParserParser) {
  46. v := getCurrentTokenText(p)
  47. if !matchRegex(v, versionRegex) {
  48. notifyErrorListeners(p, mismatched("version", v))
  49. }
  50. }
  51. func checkImportValue(p *ApiParserParser) {
  52. v := getCurrentTokenText(p)
  53. if !matchRegex(v, importValueRegex) {
  54. notifyErrorListeners(p, mismatched("import value", v))
  55. }
  56. }
  57. func checkKeyValue(p *ApiParserParser) {
  58. v := getCurrentTokenText(p)
  59. if !strings.HasPrefix(v, ":") {
  60. notifyErrorListeners(p, mismatched(":", v))
  61. }
  62. v = strings.TrimPrefix(v, ":")
  63. v = strings.TrimFunc(v, func(r rune) bool {
  64. return unicode.IsSpace(r)
  65. })
  66. setCurrentTokenText(p, v)
  67. }
  68. func checkHTTPMethod(p *ApiParserParser) {
  69. method := getCurrentTokenText(p)
  70. uppler := strings.ToUpper(method)
  71. switch uppler {
  72. case http.MethodPost, http.MethodGet, http.MethodHead,
  73. http.MethodPut, http.MethodPatch, http.MethodDelete,
  74. http.MethodConnect, http.MethodOptions, http.MethodTrace:
  75. if method != strings.ToLower(method) {
  76. notifyErrorListeners(p, expecting("http method lower case", method))
  77. }
  78. default:
  79. notifyErrorListeners(p, expecting("http method", method))
  80. }
  81. }
  82. func checkKeyword(p *ApiParserParser) {
  83. v := getCurrentTokenText(p)
  84. if IsGolangKeyWord(v) {
  85. notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", v))
  86. }
  87. }
  88. func checkKey(p *ApiParserParser) {
  89. v := getCurrentTokenText(p)
  90. if IsGolangKeyWord(v) {
  91. notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", v))
  92. }
  93. if _, ok := kind[v]; !ok {
  94. notifyErrorListeners(p, fmt.Sprintf("expecting golang basic type, found : '%s'", v))
  95. }
  96. }
  97. // IsBasicType returns true if the input argument is basic golang type
  98. func IsBasicType(text string) bool {
  99. _, ok := kind[text]
  100. return ok
  101. }
  102. // IsGolangKeyWord returns true if input argument is golang keyword, but it will be ignored which in excepts
  103. func IsGolangKeyWord(text string, excepts ...string) bool {
  104. for _, each := range excepts {
  105. if text == each {
  106. return false
  107. }
  108. }
  109. switch text {
  110. case "var", "const", "package", "import", "func", "return",
  111. "defer", "go", "select", "interface", "struct", "break", "case",
  112. "continue", "for", "fallthrough", "else", "if", "switch", "goto",
  113. "default", "chan", "type", "map", "range":
  114. return true
  115. default:
  116. return false
  117. }
  118. }
  119. func isNormal(p *ApiParserParser) bool {
  120. ct := p.GetTokenStream().(*antlr.CommonTokenStream)
  121. line := p.GetCurrentToken().GetLine()
  122. tokens := ct.GetAllTokens()
  123. var list []string
  124. for _, token := range tokens {
  125. if token.GetLine() == line {
  126. text := token.GetText()
  127. if strings.HasPrefix(text, "//") {
  128. continue
  129. }
  130. if strings.HasPrefix(text, "/*") {
  131. continue
  132. }
  133. if text == "<EOF>" {
  134. continue
  135. }
  136. if strings.TrimSpace(text) == "" {
  137. continue
  138. }
  139. list = append(list, text)
  140. }
  141. }
  142. if len(list) == 1 {
  143. t := strings.TrimPrefix(list[0], "*")
  144. if IsGolangKeyWord(t) {
  145. notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", t))
  146. }
  147. }
  148. if len(list) > 1 {
  149. if list[0] == "*" {
  150. t := strings.TrimPrefix(list[1], "*")
  151. if IsGolangKeyWord(t) {
  152. notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", t))
  153. }
  154. return false
  155. }
  156. }
  157. return len(list) > 1
  158. }
  159. // MatchTag returns a Boolean value, which returns true if it does matched, otherwise returns fase
  160. func MatchTag(v string) bool {
  161. return matchRegex(v, tagRegex)
  162. }
  163. func isInterface(p *ApiParserParser) {
  164. v := getCurrentTokenText(p)
  165. if IsGolangKeyWord(v) {
  166. notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", v))
  167. }
  168. }
  169. func getCurrentTokenText(p *ApiParserParser) string {
  170. token := p.GetCurrentToken()
  171. if token == nil {
  172. return ""
  173. }
  174. return token.GetText()
  175. }
  176. func setCurrentTokenText(p *ApiParserParser, text string) {
  177. token := p.GetCurrentToken()
  178. if token == nil {
  179. return
  180. }
  181. token.SetText(text)
  182. }
  183. func notifyErrorListeners(p *ApiParserParser, msg string) {
  184. p.NotifyErrorListeners(msg, nil, nil)
  185. }
  186. func matchRegex(text, str string) bool {
  187. re := regexp.MustCompile(str)
  188. v := re.FindString(text)
  189. text = strings.TrimFunc(text, func(r rune) bool {
  190. return unicode.IsSpace(r)
  191. })
  192. return v == text
  193. }
  194. func expecting(expecting, found string) string {
  195. return fmt.Sprintf(`expecting '%s', found input '%s'`, expecting, found)
  196. }
  197. func mismatched(expecting, found string) string {
  198. return fmt.Sprintf(`mismatched '%s', found input '%s'`, expecting, found)
  199. }