parser.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. package parser
  2. import (
  3. "fmt"
  4. "path/filepath"
  5. "unicode"
  6. "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
  7. "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
  8. "github.com/zeromicro/go-zero/tools/goctl/api/spec"
  9. )
  10. type parser struct {
  11. ast *ast.Api
  12. spec *spec.ApiSpec
  13. }
  14. // Parse parses the api file
  15. func Parse(filename string) (*spec.ApiSpec, error) {
  16. astParser := ast.NewParser(ast.WithParserPrefix(filepath.Base(filename)), ast.WithParserDebug())
  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. // ParseContent parses the api content
  30. func ParseContent(content string, filename ...string) (*spec.ApiSpec, error) {
  31. astParser := ast.NewParser()
  32. ast, err := astParser.ParseContent(content, filename...)
  33. if err != nil {
  34. return nil, err
  35. }
  36. spec := new(spec.ApiSpec)
  37. p := parser{ast: ast, spec: spec}
  38. err = p.convert2Spec()
  39. if err != nil {
  40. return nil, err
  41. }
  42. return spec, nil
  43. }
  44. func (p parser) convert2Spec() error {
  45. p.fillInfo()
  46. p.fillSyntax()
  47. p.fillImport()
  48. err := p.fillTypes()
  49. if err != nil {
  50. return err
  51. }
  52. return p.fillService()
  53. }
  54. func (p parser) fillInfo() {
  55. properties := make(map[string]string)
  56. if p.ast.Info != nil {
  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{
  66. Version: p.ast.Syntax.Version.Text(),
  67. Doc: p.stringExprs(p.ast.Syntax.DocExpr),
  68. Comment: p.stringExprs([]ast.Expr{p.ast.Syntax.CommentExpr}),
  69. }
  70. }
  71. }
  72. func (p parser) fillImport() {
  73. if len(p.ast.Import) > 0 {
  74. for _, item := range p.ast.Import {
  75. p.spec.Imports = append(p.spec.Imports, spec.Import{
  76. Value: item.Value.Text(),
  77. Doc: p.stringExprs(item.DocExpr),
  78. Comment: p.stringExprs([]ast.Expr{item.CommentExpr}),
  79. })
  80. }
  81. }
  82. }
  83. func (p parser) fillTypes() error {
  84. for _, item := range p.ast.Type {
  85. switch v := (item).(type) {
  86. case *ast.TypeStruct:
  87. var members []spec.Member
  88. for _, item := range v.Fields {
  89. members = append(members, p.fieldToMember(item))
  90. }
  91. p.spec.Types = append(p.spec.Types, spec.DefineStruct{
  92. RawName: v.Name.Text(),
  93. Members: members,
  94. Docs: p.stringExprs(v.Doc()),
  95. })
  96. default:
  97. return fmt.Errorf("unknown type %+v", v)
  98. }
  99. }
  100. var types []spec.Type
  101. for _, item := range p.spec.Types {
  102. switch v := (item).(type) {
  103. case spec.DefineStruct:
  104. var members []spec.Member
  105. for _, member := range v.Members {
  106. switch v := member.Type.(type) {
  107. case spec.DefineStruct:
  108. tp, err := p.findDefinedType(v.RawName)
  109. if err != nil {
  110. return err
  111. }
  112. member.Type = *tp
  113. }
  114. members = append(members, member)
  115. }
  116. v.Members = members
  117. types = append(types, v)
  118. default:
  119. return fmt.Errorf("unknown type %+v", v)
  120. }
  121. }
  122. p.spec.Types = types
  123. return nil
  124. }
  125. func (p parser) findDefinedType(name string) (*spec.Type, error) {
  126. for _, item := range p.spec.Types {
  127. if _, ok := item.(spec.DefineStruct); ok {
  128. if item.Name() == name {
  129. return &item, nil
  130. }
  131. }
  132. }
  133. return nil, fmt.Errorf("type %s not defined", name)
  134. }
  135. func (p parser) fieldToMember(field *ast.TypeField) spec.Member {
  136. name := ""
  137. tag := ""
  138. if !field.IsAnonymous {
  139. name = field.Name.Text()
  140. if field.Tag == nil {
  141. panic(fmt.Sprintf("error: line %d:%d field %s has no tag", field.Name.Line(), field.Name.Column(),
  142. field.Name.Text()))
  143. }
  144. tag = field.Tag.Text()
  145. }
  146. return spec.Member{
  147. Name: name,
  148. Type: p.astTypeToSpec(field.DataType),
  149. Tag: tag,
  150. Comment: p.commentExprs(field.Comment()),
  151. Docs: p.stringExprs(field.Doc()),
  152. IsInline: field.IsAnonymous,
  153. }
  154. }
  155. func (p parser) astTypeToSpec(in ast.DataType) spec.Type {
  156. switch v := (in).(type) {
  157. case *ast.Literal:
  158. raw := v.Literal.Text()
  159. if api.IsBasicType(raw) {
  160. return spec.PrimitiveType{
  161. RawName: raw,
  162. }
  163. }
  164. return spec.DefineStruct{
  165. RawName: raw,
  166. }
  167. case *ast.Interface:
  168. return spec.InterfaceType{RawName: v.Literal.Text()}
  169. case *ast.Map:
  170. return spec.MapType{RawName: v.MapExpr.Text(), Key: v.Key.Text(), Value: p.astTypeToSpec(v.Value)}
  171. case *ast.Array:
  172. return spec.ArrayType{RawName: v.ArrayExpr.Text(), Value: p.astTypeToSpec(v.Literal)}
  173. case *ast.Pointer:
  174. raw := v.Name.Text()
  175. if api.IsBasicType(raw) {
  176. return spec.PointerType{RawName: v.PointerExpr.Text(), Type: spec.PrimitiveType{RawName: raw}}
  177. }
  178. return spec.PointerType{RawName: v.PointerExpr.Text(), Type: spec.DefineStruct{RawName: raw}}
  179. }
  180. panic(fmt.Sprintf("unspported type %+v", in))
  181. }
  182. func (p parser) stringExprs(docs []ast.Expr) []string {
  183. var result []string
  184. for _, item := range docs {
  185. if item == nil {
  186. continue
  187. }
  188. result = append(result, item.Text())
  189. }
  190. return result
  191. }
  192. func (p parser) commentExprs(comment ast.Expr) string {
  193. if comment == nil {
  194. return ""
  195. }
  196. return comment.Text()
  197. }
  198. func (p parser) fillService() error {
  199. var groups []spec.Group
  200. for _, item := range p.ast.Service {
  201. var group spec.Group
  202. p.fillAtServer(item, &group)
  203. for _, astRoute := range item.ServiceApi.ServiceRoute {
  204. route := spec.Route{
  205. AtServerAnnotation: spec.Annotation{},
  206. Method: astRoute.Route.Method.Text(),
  207. Path: astRoute.Route.Path.Text(),
  208. Doc: p.stringExprs(astRoute.Route.DocExpr),
  209. Comment: p.stringExprs([]ast.Expr{astRoute.Route.CommentExpr}),
  210. }
  211. if astRoute.AtHandler != nil {
  212. route.Handler = astRoute.AtHandler.Name.Text()
  213. route.HandlerDoc = append(route.HandlerDoc, p.stringExprs(astRoute.AtHandler.DocExpr)...)
  214. route.HandlerComment = append(route.HandlerComment, p.stringExprs([]ast.Expr{astRoute.AtHandler.CommentExpr})...)
  215. }
  216. err := p.fillRouteAtServer(astRoute, &route)
  217. if err != nil {
  218. return err
  219. }
  220. if astRoute.Route.Req != nil {
  221. route.RequestType = p.astTypeToSpec(astRoute.Route.Req.Name)
  222. }
  223. if astRoute.Route.Reply != nil {
  224. route.ResponseType = p.astTypeToSpec(astRoute.Route.Reply.Name)
  225. }
  226. if astRoute.AtDoc != nil {
  227. properties := make(map[string]string)
  228. for _, kv := range astRoute.AtDoc.Kv {
  229. properties[kv.Key.Text()] = kv.Value.Text()
  230. }
  231. route.AtDoc.Properties = properties
  232. if astRoute.AtDoc.LineDoc != nil {
  233. route.AtDoc.Text = astRoute.AtDoc.LineDoc.Text()
  234. }
  235. }
  236. err = p.fillRouteType(&route)
  237. if err != nil {
  238. return err
  239. }
  240. group.Routes = append(group.Routes, route)
  241. name := item.ServiceApi.Name.Text()
  242. if len(p.spec.Service.Name) > 0 && p.spec.Service.Name != name {
  243. return fmt.Errorf("multiple service names defined %s and %s", name, p.spec.Service.Name)
  244. }
  245. p.spec.Service.Name = name
  246. }
  247. groups = append(groups, group)
  248. }
  249. p.spec.Service.Groups = groups
  250. return nil
  251. }
  252. func (p parser) fillRouteAtServer(astRoute *ast.ServiceRoute, route *spec.Route) error {
  253. if astRoute.AtServer != nil {
  254. properties := make(map[string]string)
  255. for _, kv := range astRoute.AtServer.Kv {
  256. properties[kv.Key.Text()] = kv.Value.Text()
  257. }
  258. route.AtServerAnnotation.Properties = properties
  259. if len(route.Handler) == 0 {
  260. route.Handler = properties["handler"]
  261. }
  262. if len(route.Handler) == 0 {
  263. return fmt.Errorf("missing handler annotation for %q", route.Path)
  264. }
  265. for _, char := range route.Handler {
  266. if !unicode.IsDigit(char) && !unicode.IsLetter(char) {
  267. return fmt.Errorf("route [%s] handler [%s] invalid, handler name should only contains letter or digit",
  268. route.Path, route.Handler)
  269. }
  270. }
  271. }
  272. return nil
  273. }
  274. func (p parser) fillAtServer(item *ast.Service, group *spec.Group) {
  275. if item.AtServer != nil {
  276. properties := make(map[string]string)
  277. for _, kv := range item.AtServer.Kv {
  278. properties[kv.Key.Text()] = kv.Value.Text()
  279. }
  280. group.Annotation.Properties = properties
  281. }
  282. }
  283. func (p parser) fillRouteType(route *spec.Route) error {
  284. if route.RequestType != nil {
  285. switch route.RequestType.(type) {
  286. case spec.DefineStruct:
  287. tp, err := p.findDefinedType(route.RequestType.Name())
  288. if err != nil {
  289. return err
  290. }
  291. route.RequestType = *tp
  292. }
  293. }
  294. if route.ResponseType != nil {
  295. switch route.ResponseType.(type) {
  296. case spec.DefineStruct:
  297. tp, err := p.findDefinedType(route.ResponseType.Name())
  298. if err != nil {
  299. return err
  300. }
  301. route.ResponseType = *tp
  302. }
  303. }
  304. return nil
  305. }