parser.go 7.4 KB

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