parser.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package parser
  2. import (
  3. "errors"
  4. "fmt"
  5. "path/filepath"
  6. "unicode"
  7. "github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
  8. "github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
  9. "github.com/tal-tech/go-zero/tools/goctl/api/spec"
  10. )
  11. type parser struct {
  12. ast *ast.Api
  13. spec *spec.ApiSpec
  14. }
  15. func Parse(filename string) (*spec.ApiSpec, error) {
  16. astParser := ast.NewParser(ast.WithParserPrefix(filepath.Base(filename)))
  17. ast, err := astParser.Parse(filename)
  18. if err != nil {
  19. return nil, err
  20. }
  21. spec := new(spec.ApiSpec)
  22. p := parser{ast: ast, spec: spec}
  23. err = p.convert2Spec()
  24. if err != nil {
  25. return nil, err
  26. }
  27. return spec, nil
  28. }
  29. func ParseContent(content string) (*spec.ApiSpec, error) {
  30. astParser := ast.NewParser()
  31. ast, err := astParser.ParseContent(content)
  32. if err != nil {
  33. return nil, err
  34. }
  35. spec := new(spec.ApiSpec)
  36. p := parser{ast: ast, spec: spec}
  37. err = p.convert2Spec()
  38. if err != nil {
  39. return nil, err
  40. }
  41. return spec, nil
  42. }
  43. func (p parser) convert2Spec() error {
  44. p.fillInfo()
  45. p.fillSyntax()
  46. p.fillImport()
  47. err := p.fillTypes()
  48. if err != nil {
  49. return err
  50. }
  51. return p.fillService()
  52. }
  53. func (p parser) fillInfo() {
  54. var properties = make(map[string]string, 0)
  55. if p.ast.Info != nil {
  56. p.spec.Info = spec.Info{}
  57. for _, kv := range p.ast.Info.Kvs {
  58. properties[kv.Key.Text()] = kv.Value.Text()
  59. }
  60. }
  61. p.spec.Info.Properties = properties
  62. }
  63. func (p parser) fillSyntax() {
  64. if p.ast.Syntax != nil {
  65. p.spec.Syntax = spec.ApiSyntax{Version: p.ast.Syntax.Version.Text()}
  66. }
  67. }
  68. func (p parser) fillImport() {
  69. if len(p.ast.Import) > 0 {
  70. for _, item := range p.ast.Import {
  71. p.spec.Imports = append(p.spec.Imports, spec.Import{Value: item.Value.Text()})
  72. }
  73. }
  74. }
  75. func (p parser) fillTypes() error {
  76. for _, item := range p.ast.Type {
  77. switch v := (item).(type) {
  78. case *ast.TypeStruct:
  79. var members []spec.Member
  80. for _, item := range v.Fields {
  81. members = append(members, p.fieldToMember(item))
  82. }
  83. p.spec.Types = append(p.spec.Types, spec.DefineStruct{
  84. RawName: v.Name.Text(),
  85. Members: members,
  86. Docs: p.stringExprs(v.Doc()),
  87. })
  88. default:
  89. return errors.New(fmt.Sprintf("unknown type %+v", v))
  90. }
  91. }
  92. for _, item := range p.spec.Types {
  93. switch v := (item).(type) {
  94. case spec.DefineStruct:
  95. for _, member := range v.Members {
  96. switch v := member.Type.(type) {
  97. case spec.DefineStruct:
  98. tp, err := p.findDefinedType(v.RawName)
  99. if err != nil {
  100. return err
  101. } else {
  102. member.Type = *tp
  103. }
  104. }
  105. }
  106. default:
  107. return errors.New(fmt.Sprintf("unknown type %+v", v))
  108. }
  109. }
  110. return nil
  111. }
  112. func (p parser) findDefinedType(name string) (*spec.Type, error) {
  113. for _, item := range p.spec.Types {
  114. if _, ok := item.(spec.DefineStruct); ok {
  115. if item.Name() == name {
  116. return &item, nil
  117. }
  118. }
  119. }
  120. return nil, errors.New(fmt.Sprintf("type %s not defined", name))
  121. }
  122. func (p parser) fieldToMember(field *ast.TypeField) spec.Member {
  123. var name = ""
  124. var tag = ""
  125. if !field.IsAnonymous {
  126. name = field.Name.Text()
  127. tag = field.Tag.Text()
  128. }
  129. return spec.Member{
  130. Name: name,
  131. Type: p.astTypeToSpec(field.DataType),
  132. Tag: tag,
  133. Comment: p.commentExprs(field.Comment()),
  134. Docs: p.stringExprs(field.Doc()),
  135. IsInline: field.IsAnonymous,
  136. }
  137. }
  138. func (p parser) astTypeToSpec(in ast.DataType) spec.Type {
  139. switch v := (in).(type) {
  140. case *ast.Literal:
  141. raw := v.Literal.Text()
  142. if api.IsBasicType(raw) {
  143. return spec.PrimitiveType{RawName: raw}
  144. } else {
  145. return spec.DefineStruct{RawName: raw}
  146. }
  147. case *ast.Interface:
  148. return spec.InterfaceType{RawName: v.Literal.Text()}
  149. case *ast.Map:
  150. return spec.MapType{RawName: v.MapExpr.Text(), Key: v.Key.Text(), Value: p.astTypeToSpec(v.Value)}
  151. case *ast.Array:
  152. return spec.ArrayType{RawName: v.ArrayExpr.Text(), Value: p.astTypeToSpec(v.Literal)}
  153. case *ast.Pointer:
  154. raw := v.Name.Text()
  155. if api.IsBasicType(raw) {
  156. return spec.PointerType{RawName: v.PointerExpr.Text(), Type: spec.PrimitiveType{RawName: raw}}
  157. } else {
  158. return spec.PointerType{RawName: v.PointerExpr.Text(), Type: spec.DefineStruct{RawName: raw}}
  159. }
  160. }
  161. panic(fmt.Sprintf("unspported type %+v", in))
  162. }
  163. func (p parser) stringExprs(docs []ast.Expr) []string {
  164. var result []string
  165. for _, item := range docs {
  166. result = append(result, item.Text())
  167. }
  168. return result
  169. }
  170. func (p parser) commentExprs(comment ast.Expr) string {
  171. if comment == nil {
  172. return ""
  173. }
  174. return comment.Text()
  175. }
  176. func (p parser) fillService() error {
  177. var groups []spec.Group
  178. for _, item := range p.ast.Service {
  179. var group spec.Group
  180. if item.AtServer != nil {
  181. var properties = make(map[string]string, 0)
  182. for _, kv := range item.AtServer.Kv {
  183. properties[kv.Key.Text()] = kv.Value.Text()
  184. }
  185. group.Annotation.Properties = properties
  186. }
  187. for _, astRoute := range item.ServiceApi.ServiceRoute {
  188. route := spec.Route{
  189. Annotation: spec.Annotation{},
  190. Method: astRoute.Route.Method.Text(),
  191. Path: astRoute.Route.Path.Text(),
  192. }
  193. if astRoute.AtHandler != nil {
  194. route.Handler = astRoute.AtHandler.Name.Text()
  195. }
  196. if astRoute.AtServer != nil {
  197. var properties = make(map[string]string, 0)
  198. for _, kv := range astRoute.AtServer.Kv {
  199. properties[kv.Key.Text()] = kv.Value.Text()
  200. }
  201. route.Annotation.Properties = properties
  202. if len(route.Handler) == 0 {
  203. route.Handler = properties["handler"]
  204. }
  205. if len(route.Handler) == 0 {
  206. return fmt.Errorf("missing handler annotation for %q", route.Path)
  207. }
  208. for _, char := range route.Handler {
  209. if !unicode.IsDigit(char) && !unicode.IsLetter(char) {
  210. return errors.New(fmt.Sprintf("route [%s] handler [%s] invalid, handler name should only contains letter or digit",
  211. route.Path, route.Handler))
  212. }
  213. }
  214. }
  215. if astRoute.Route.Req != nil {
  216. route.RequestType = p.astTypeToSpec(astRoute.Route.Req.Name)
  217. }
  218. if astRoute.Route.Reply != nil {
  219. route.ResponseType = p.astTypeToSpec(astRoute.Route.Reply.Name)
  220. }
  221. err := p.fillRouteType(&route)
  222. if err != nil {
  223. return err
  224. }
  225. group.Routes = append(group.Routes, route)
  226. name := item.ServiceApi.Name.Text()
  227. if len(p.spec.Service.Name) > 0 && p.spec.Service.Name != name {
  228. return errors.New(fmt.Sprintf("mulit service name defined %s and %s", name, p.spec.Service.Name))
  229. }
  230. p.spec.Service.Name = name
  231. }
  232. groups = append(groups, group)
  233. }
  234. p.spec.Service.Groups = groups
  235. return nil
  236. }
  237. func (p parser) fillRouteType(route *spec.Route) error {
  238. if route.RequestType != nil {
  239. switch route.RequestType.(type) {
  240. case spec.DefineStruct:
  241. tp, err := p.findDefinedType(route.RequestType.Name())
  242. if err != nil {
  243. return err
  244. }
  245. route.RequestType = *tp
  246. }
  247. }
  248. if route.ResponseType != nil {
  249. switch route.ResponseType.(type) {
  250. case spec.DefineStruct:
  251. tp, err := p.findDefinedType(route.ResponseType.Name())
  252. if err != nil {
  253. return err
  254. }
  255. route.ResponseType = *tp
  256. }
  257. }
  258. return nil
  259. }