123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- package api
- import (
- "fmt"
- "net/http"
- "regexp"
- "strings"
- "unicode"
- "github.com/zeromicro/antlr"
- )
- const (
- versionRegex = `(?m)"v[1-9][0-9]*"`
- importValueRegex = `(?m)"\/?(([a-zA-Z0-9.]+)+(\/?){1})+([a-zA-Z0-9]+)+\.api"`
- tagRegex = `(?m)\x60[a-z]+:".+"\x60`
- )
- var (
- holder = struct{}{}
- kind = map[string]struct{}{
- "bool": holder,
- "int": holder,
- "int8": holder,
- "int16": holder,
- "int32": holder,
- "int64": holder,
- "uint": holder,
- "uint8": holder,
- "uint16": holder,
- "uint32": holder,
- "uint64": holder,
- "uintptr": holder,
- "float32": holder,
- "float64": holder,
- "complex64": holder,
- "complex128": holder,
- "string": holder,
- "byte": holder,
- "rune": holder,
- }
- )
- func match(p *ApiParserParser, text string) {
- v := getCurrentTokenText(p)
- if v != text {
- notifyErrorListeners(p, expecting(text, v))
- }
- }
- func checkVersion(p *ApiParserParser) {
- v := getCurrentTokenText(p)
- if !matchRegex(v, versionRegex) {
- notifyErrorListeners(p, mismatched("version", v))
- }
- }
- func checkImportValue(p *ApiParserParser) {
- v := getCurrentTokenText(p)
- if !matchRegex(v, importValueRegex) {
- notifyErrorListeners(p, mismatched("import value", v))
- }
- }
- func checkKeyValue(p *ApiParserParser) {
- v := getCurrentTokenText(p)
- if !strings.HasPrefix(v, ":") {
- notifyErrorListeners(p, mismatched(":", v))
- }
- v = strings.TrimPrefix(v, ":")
- v = strings.TrimFunc(v, func(r rune) bool {
- return unicode.IsSpace(r)
- })
- setCurrentTokenText(p, v)
- }
- func checkHTTPMethod(p *ApiParserParser) {
- method := getCurrentTokenText(p)
- uppler := strings.ToUpper(method)
- switch uppler {
- case http.MethodPost, http.MethodGet, http.MethodHead,
- http.MethodPut, http.MethodPatch, http.MethodDelete,
- http.MethodConnect, http.MethodOptions, http.MethodTrace:
- if method != strings.ToLower(method) {
- notifyErrorListeners(p, expecting("http method lower case", method))
- }
- default:
- notifyErrorListeners(p, expecting("http method", method))
- }
- }
- func checkKeyword(p *ApiParserParser) {
- v := getCurrentTokenText(p)
- if IsGolangKeyWord(v) {
- notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", v))
- }
- }
- func checkKey(p *ApiParserParser) {
- v := getCurrentTokenText(p)
- if IsGolangKeyWord(v) {
- notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", v))
- }
- if _, ok := kind[v]; !ok {
- notifyErrorListeners(p, fmt.Sprintf("expecting golang basic type, found : '%s'", v))
- }
- }
- // IsBasicType returns true if the input argument is basic golang type
- func IsBasicType(text string) bool {
- _, ok := kind[text]
- return ok
- }
- // IsGolangKeyWord returns true if input argument is golang keyword, but it will be ignored which in excepts
- func IsGolangKeyWord(text string, excepts ...string) bool {
- for _, each := range excepts {
- if text == each {
- return false
- }
- }
- switch text {
- case "var", "const", "package", "import", "func", "return",
- "defer", "go", "select", "interface", "struct", "break", "case",
- "continue", "for", "fallthrough", "else", "if", "switch", "goto",
- "default", "chan", "type", "map", "range":
- return true
- default:
- return false
- }
- }
- func isNormal(p *ApiParserParser) bool {
- ct := p.GetTokenStream().(*antlr.CommonTokenStream)
- line := p.GetCurrentToken().GetLine()
- tokens := ct.GetAllTokens()
- var list []string
- for _, token := range tokens {
- if token.GetLine() == line {
- text := token.GetText()
- if strings.HasPrefix(text, "//") {
- continue
- }
- if strings.HasPrefix(text, "/*") {
- continue
- }
- if text == "<EOF>" {
- continue
- }
- if strings.TrimSpace(text) == "" {
- continue
- }
- list = append(list, text)
- }
- }
- if len(list) == 1 {
- t := strings.TrimPrefix(list[0], "*")
- if IsGolangKeyWord(t) {
- notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", t))
- }
- }
- if len(list) > 1 {
- if list[0] == "*" {
- t := strings.TrimPrefix(list[1], "*")
- if IsGolangKeyWord(t) {
- notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", t))
- }
- return false
- }
- }
- return len(list) > 1
- }
- // MatchTag returns a Boolean value, which returns true if it does matched, otherwise returns fase
- func MatchTag(v string) bool {
- return matchRegex(v, tagRegex)
- }
- func isInterface(p *ApiParserParser) {
- v := getCurrentTokenText(p)
- if IsGolangKeyWord(v) {
- notifyErrorListeners(p, fmt.Sprintf("expecting ID, found golang keyword: '%s'", v))
- }
- }
- func getCurrentTokenText(p *ApiParserParser) string {
- token := p.GetCurrentToken()
- if token == nil {
- return ""
- }
- return token.GetText()
- }
- func setCurrentTokenText(p *ApiParserParser, text string) {
- token := p.GetCurrentToken()
- if token == nil {
- return
- }
- token.SetText(text)
- }
- func notifyErrorListeners(p *ApiParserParser, msg string) {
- p.NotifyErrorListeners(msg, nil, nil)
- }
- func matchRegex(text, str string) bool {
- re := regexp.MustCompile(str)
- v := re.FindString(text)
- text = strings.TrimFunc(text, func(r rune) bool {
- return unicode.IsSpace(r)
- })
- return v == text
- }
- func expecting(expecting, found string) string {
- return fmt.Sprintf(`expecting '%s', found input '%s'`, expecting, found)
- }
- func mismatched(expecting, found string) string {
- return fmt.Sprintf(`mismatched '%s', found input '%s'`, expecting, found)
- }
|