parser.go 9.2 KB

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