gen.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. package generator
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. "git.eugeniocarvalho.dev/eugeniucarvalho/utils"
  7. G "github.com/dave/jennifer/jen"
  8. )
  9. const (
  10. // UTILS = "git.gojus.com.br/eugeniucarvalho/utils"
  11. // GENERATOR_BASE = "git.gojus.com.br/eugeniucarvalho/gg/generator"
  12. )
  13. type Generator struct {
  14. Language string `json:"language"`
  15. Keywords []string `json:"keywords"`
  16. Commands map[string]*Command `json:"commands"`
  17. BuiltIn map[string]*Command `json:"builtIn"`
  18. Output string
  19. }
  20. type Command struct {
  21. Name string `json:"name"`
  22. IgnoreGen bool `json:"ignoreGen"`
  23. Delimiter string `json:"delimiter"`
  24. MethodName string `json:"-"`
  25. Template string `json:"template"`
  26. ParamList []Param `json:"paramList,omitempty"`
  27. Description string `json:"description,omitempty"`
  28. RenderChildrenAs string `json:"readChildrenAs,omitempty"`
  29. ChildrenRenderMode string `json:"childrenRenderMode,omitempty"`
  30. }
  31. type Param struct {
  32. Name string `json:"name"`
  33. Type string `json:"type"`
  34. }
  35. func New(file string) (*Generator, error) {
  36. data, err := utils.FileGetContents(file)
  37. if err == nil {
  38. g := &Generator{}
  39. if err = json.Unmarshal([]byte(data), g); err == nil {
  40. // g.BuiltInRegister()
  41. return g, nil
  42. }
  43. }
  44. return nil, err
  45. }
  46. func (g *Generator) AddCommand(key string, cmd *Command) {
  47. g.Keywords = append(g.Keywords, key)
  48. g.Commands[key] = cmd
  49. }
  50. func (g *Generator) Gen(folder string) (err error) {
  51. g.Output = folder
  52. file := G.NewFile(g.Language)
  53. // Cria interface com todos os metodos
  54. if err = g.GenBaseInterface(file); err != nil {
  55. return err
  56. }
  57. // Cria todas as funcoes staticas com os comandos basicos
  58. // g.GenBuiltIn(file)
  59. fmt.Printf("Filepath: %s\n", g.FilePath("struct.go"))
  60. if err = file.Save(g.FilePath(g.Language + ".go")); err != nil {
  61. panic(err)
  62. }
  63. return nil
  64. }
  65. func (g *Generator) FilePath(name string) string {
  66. return fmt.Sprintf("%s/%s/%s", g.Output, g.Language, name)
  67. }
  68. func (g *Generator) GenBaseInterface(file *G.File) (err error) {
  69. // file.Type().Id("File").StructFunc(func(g *G.Group) {
  70. // g.Add(G.Id("Group"))
  71. // g.Add(G.Id("Name").Id("string"))
  72. // }).Line()
  73. // file.Func().Id("NewFile").Params(G.Id("file").Id("string")).Params(G.Op("*").Id("File")).Block(
  74. // G.Return(G.Op("&").Id("File").Values(G.Dict{
  75. // G.Id("Name"): G.Id("file"),
  76. // })),
  77. // )
  78. // file.Func().Params(G.Id("f").Op("*").Id("File")).Id("Save").Params().Params(G.Id("error")).Block(
  79. // G.Return(G.Qual(UTILS, "FilePutContents").Call(
  80. // G.Id("f").Dot("Name"),
  81. // G.Id("f").Dot("GoString").Call(),
  82. // G.Lit(777),
  83. // )),
  84. // )
  85. // file.Comment("Entidade representa menor unidade de Statement.")
  86. // file.Type().Id("Stmt").StructFunc(func(g *G.Group) {
  87. // g.Add(G.Id("Group"))
  88. // g.Add(G.Id("value").Id("interface{}"))
  89. // g.Add(G.Id("template").Id("string"))
  90. // g.Add(G.Id("Separete").Id("string"))
  91. // // g.Add(G.Id("Childrens").Index().Id("CodeInterface"))
  92. // }).Line()
  93. // file.Func().Params(
  94. // G.Id("s").Op("*").Id("Stmt"),
  95. // ).Id("Render").Params(
  96. // G.Id("buffer").Op("*").Qual("bytes", "Buffer"),
  97. // // G.Id("buffer").Op("*").Id("bytes").Dot("Buffer"),
  98. // ).Params(
  99. // G.Id("err").Id("error"),
  100. // ).Block(
  101. // G.For(
  102. // G.List(G.Id("_"), G.Id("s")).Op(":=").Range().Id("s").Dot("Stmts"),
  103. // ).Block(
  104. // G.Id("err").Op("=").Id("s").Dot("Render").Call(G.Id("buffer")),
  105. // ).Line().Return(G.Empty()),
  106. // )
  107. // file.Comment("Root node group of Statement.")
  108. // file.Type().Id("Group").StructFunc(func(g *G.Group) {
  109. // g.Add(G.Qual(GENERATOR_BASE, "Group"))
  110. // // g.Add(G.Id("Stmts").Index().Id("CodeInterface"))
  111. // }).Line()
  112. // file.Comment("Metodo realiza a renderização de um grupo e todos os seus statements.")
  113. // file.Func().Params(
  114. // G.Id("g").Op("*").Id("Group"),
  115. // ).Id("Render").Params(
  116. // G.Id("buffer").Op("*").Qual("bytes", "Buffer"),
  117. // // G.Id("buffer").Op("*").Id("bytes").Dot("Buffer"),
  118. // ).Params(
  119. // G.Id("err").Id("error"),
  120. // ).Block(
  121. // G.For(
  122. // G.List(G.Id("_"), G.Id("s")).Op(":=").Range().Id("g").Dot("Stmts"),
  123. // ).Block(
  124. // G.Id("err").Op("=").Id("s").Dot("Render").Call(G.Id("buffer")),
  125. // ).Line().Return(G.Empty()),
  126. // )
  127. // file.Comment("Metodo Gera a string do arquivo.")
  128. // file.Func().Params(
  129. // G.Id("g").Op("*").Id("Group"),
  130. // ).Id("GoString").Params().Params(
  131. // G.Id("string"),
  132. // ).Block(
  133. // G.Id("buf").Op(":=").Qual("bytes", "Buffer").Values(),
  134. // // G.Id("buf").Op(":=").Id("bytes").Dot("Buffer"),
  135. // G.If(
  136. // G.Id("err").Op(":=").Id("g").Dot("Render").Call(G.Op("&").Id("buf")),
  137. // G.Id("err").Op("!=").Nil(),
  138. // ).Block(
  139. // G.Id("panic").Call(G.Id("err")),
  140. // ).Line().Return(G.Id("buf").Dot("String").Call()),
  141. // ).Line()
  142. // file.Func().Id("NewGroup").Params().Op("*").Id("Group").Block(
  143. // G.Return(G.Op("&").Id("Group").Values()),
  144. // ).Line()
  145. var (
  146. cmd *Command
  147. uppKey string
  148. found bool
  149. // interfacesMethods = []*G.Statement{}
  150. method *G.Statement
  151. methods = []string{}
  152. )
  153. codeInterface := file.Type().Id("CodeInterface")
  154. interfaces := G.Statement{}
  155. // Adiciona a importacao da interface do gerador
  156. // interfaces = append(interfaces, G.Qual(GENERATOR_BASE, "CodeInterface"))
  157. interfaces = append(interfaces, G.Id("BaseCodeInterface"))
  158. // interfaces = append(interfaces, G.Id("Render").Params(
  159. // G.Id("buffer").Op("*").Qual("bytes", "Buffer"),
  160. // ).Params(G.Id("error")))
  161. for _, key := range g.Keywords {
  162. uppKey = strings.Title(key)
  163. methods = append(methods, uppKey)
  164. if cmd, found = g.Commands[key]; found {
  165. cmd.Name = key
  166. cmd.MethodName = uppKey
  167. interfaces = genCmd(file, cmd, interfaces)
  168. } else {
  169. // Todos os metodos para keywords genericas sem template
  170. // são tratados aqui.
  171. interfaces = append(interfaces, G.Id(uppKey).Params().Params(G.Op("*").Id("Group")))
  172. method = G.Func().Params(
  173. G.Id("g").Op("*").Id("Group"),
  174. ).Id(uppKey).Params().Params(G.Op("*").Id("Group"))
  175. file.Add(method.Clone().Block(
  176. G.Id("s").Op(":=").Op("&").Id("Stmt").Values(G.Dict{
  177. G.Id("Value"): G.Lit(key),
  178. G.Id("Template"): G.Lit(" %s "),
  179. }),
  180. G.Id("g").Dot("Stmts").Op("=").Append(
  181. G.Id("g").Dot("Stmts"),
  182. G.Id("s"),
  183. ),
  184. G.Return(G.Id("g")),
  185. ).Line())
  186. ModuleFunction(file, uppKey, G.Statement{}, []string{})
  187. }
  188. }
  189. codeInterface.Interface(interfaces...)
  190. return
  191. }
  192. func genCmd(file *G.File, cmd *Command, interfaces G.Statement) G.Statement {
  193. var (
  194. p *G.Statement
  195. params = G.Statement{}
  196. paramsKeys = []string{}
  197. paramsTypes = []string{}
  198. )
  199. file.Func().Params(
  200. G.Id("g").Op("*").Id("Group"),
  201. ).Id(cmd.MethodName).ParamsFunc(func(g *G.Group) {
  202. if len(cmd.ParamList) == 0 {
  203. return
  204. }
  205. for _, param := range cmd.ParamList {
  206. p = G.Id(param.Name).Id(param.Type)
  207. g.Add(p)
  208. paramsKeys = append(paramsKeys, param.Name)
  209. paramsTypes = append(paramsTypes, param.Type)
  210. params = append(params, p)
  211. }
  212. interfaces = append(interfaces, G.Id(cmd.MethodName).Params(params...).Params(G.Op("*").Id("Group")))
  213. }).Params(
  214. G.Op("*").Id("Group"),
  215. ).BlockFunc(func(g *G.Group) {
  216. // g.Add(G.Id("s").Op(":=").Op("&").Qual(GENERATOR_BASE, "Stmt").ValuesFunc(func(x *G.Group) {
  217. g.Add(G.Id("s").Op(":=").Op("&").Id("Stmt").ValuesFunc(func(x *G.Group) {
  218. var (
  219. value interface{}
  220. // lit bool
  221. lit = true
  222. )
  223. x.Add(G.Id("Template").Op(":").Lit(fmt.Sprintf(" %s ", cmd.Template)))
  224. for k, typ := range paramsTypes {
  225. // fmt.Println("---", k, typ, paramsKeys[k])
  226. switch {
  227. case typ == "string" || typ == "interface{}":
  228. value = paramsKeys[k]
  229. lit = false
  230. case typ[0:3] == "...":
  231. x.Add(
  232. // G.Id("Group").Op(":").Id("Group").Values(
  233. // G.Id("Group").Op(":").Qual(GENERATOR_BASE, "Group").Values(G.Dict{
  234. G.Id("Group").Op(":").Id("Group").Values(G.Dict{
  235. G.Id("Stmts"): G.Id(paramsKeys[k]),
  236. }),
  237. )
  238. paramsKeys[k] += "..."
  239. default:
  240. // x.Add(G.Id("Group").Op(":").Id("Group").Values(
  241. // G.Qual(GENERATOR_BASE, "Group").Op(":").Qual(GENERATOR_BASE, "Group").Values(G.Dict{
  242. // G.Id("Stmts"): G.Index().Id("CodeInterface").Values(G.Id(paramsKeys[k])),
  243. // }),
  244. // ))
  245. // x.Add(G.Id("Group").Op(":").Qual(GENERATOR_BASE, "Group").Values(G.Dict{
  246. // G.Id("Stmts"): G.Index().Qual(GENERATOR_BASE, "CodeInterface").Values(G.Id(paramsKeys[k])),
  247. // }))
  248. x.Add(G.Id("Group").Op(":").Id("Group").Values(G.Dict{
  249. G.Id("Stmts"): G.Index().Id("CodeInterface").Values(G.Id(paramsKeys[k])),
  250. }))
  251. }
  252. break
  253. }
  254. if value == nil {
  255. value = cmd.Name
  256. }
  257. if lit {
  258. x.Add(G.Id("Value").Op(":").Lit(value))
  259. } else {
  260. x.Add(G.Id("Value").Op(":").Id(value.(string)))
  261. }
  262. if cmd.Delimiter != "" {
  263. x.Add(G.Id("Delimiter").Op(":").Lit(cmd.Delimiter))
  264. }
  265. }))
  266. g.Add(G.Id("g").Dot("Stmts").Op("=").Append(
  267. G.Id("g").Dot("Stmts"),
  268. G.Id("s"),
  269. ))
  270. g.Add(G.Return(G.Id("g")))
  271. }).Line()
  272. ModuleFunction(file, cmd.MethodName, params, paramsKeys)
  273. return interfaces
  274. }
  275. func ModuleFunction(file *G.File, method string, params G.Statement, paramsKeys []string) {
  276. file.Func().Id(method).Params(params...).Params(G.Op("*").Id("Group")).Block(
  277. G.Return(G.Id("NewGroup").Call().Dot(method).CallFunc(func(g *G.Group) {
  278. for _, key := range paramsKeys {
  279. g.Add(G.Id(key))
  280. }
  281. })),
  282. ).Line()
  283. }
  284. // func (g *Generator) BuiltInRegister() {
  285. // if g.BuiltIn == nil {
  286. // g.BuiltIn = map[string]*Command{}
  287. // }
  288. // fmt.Println("Add built in")
  289. // g.AddBuiltIn("params", &Command{
  290. // Template: "(%s)",
  291. // ParamList: []Param{
  292. // Param{
  293. // Name: "params",
  294. // Type: "...CodeInterface",
  295. // },
  296. // },
  297. // Description: "Parameter definition in function declaration.",
  298. // })
  299. // g.AddBuiltIn("op", &Command{
  300. // Template: " %s ",
  301. // ParamList: []Param{
  302. // Param{
  303. // Name: "op",
  304. // Type: "string",
  305. // },
  306. // },
  307. // Description: "Representa um operando {=,!=,>,<,>=,<=,-,+,*,/,%}.",
  308. // })
  309. // g.AddBuiltIn("block", &Command{
  310. // // Template: " {\n%s\n}\n",
  311. // Template: " {%s}\n",
  312. // RenderChildrenAs: "lines",
  313. // ParamList: []Param{
  314. // Param{
  315. // Name: "stmts",
  316. // Type: "...CodeInterface",
  317. // },
  318. // },
  319. // })
  320. // g.AddBuiltIn("call", &Command{
  321. // Template: "(%s)",
  322. // ParamList: []Param{
  323. // Param{
  324. // Name: "params",
  325. // Type: "CodeInterface",
  326. // },
  327. // },
  328. // Description: "Generete a call of function or method. The parameter is um List Stmt.",
  329. // })
  330. // g.AddBuiltIn("id", &Command{
  331. // Template: "%s",
  332. // ParamList: []Param{
  333. // Param{
  334. // Name: "stmt",
  335. // Type: "string",
  336. // },
  337. // },
  338. // })
  339. // g.AddBuiltIn("comment", &Command{
  340. // Template: "\n//%s\n",
  341. // IgnoreGen: true,
  342. // ParamList: []Param{
  343. // Param{
  344. // Name: "stmt",
  345. // Type: "string",
  346. // },
  347. // },
  348. // })
  349. // g.AddBuiltIn("lit", &Command{
  350. // Template: "%s",
  351. // IgnoreGen: true,
  352. // ParamList: []Param{
  353. // Param{
  354. // Name: "stmt",
  355. // Type: "interface{}",
  356. // },
  357. // },
  358. // })
  359. // g.AddBuiltIn("index", &Command{
  360. // Template: "[%s]",
  361. // ParamList: []Param{
  362. // Param{
  363. // Name: "index",
  364. // Type: "CodeInterface",
  365. // },
  366. // },
  367. // Description: "Gen a index access. The parameter is a List",
  368. // })
  369. // }
  370. // func (g *Generator) AddBuiltIn(key string, cmd *Command) {
  371. // // g.BuiltIn = append(g.BuiltIn, key)
  372. // g.BuiltIn[key] = cmd
  373. // }
  374. // func (g *Generator) GenBuiltIn(file *G.File) {
  375. // var (
  376. // params *G.Statement
  377. // paramsKeys []string
  378. // name string
  379. // typ string
  380. // ret string
  381. // )
  382. // for method, cmd := range g.BuiltIn {
  383. // paramsKeys = []string{}
  384. // method = strings.Title(method)
  385. // params = &G.Statement{}
  386. // for _, param := range cmd.ParamList {
  387. // name = param.Name
  388. // typ = param.Type
  389. // ret = ""
  390. // if strings.Contains(typ, "...") {
  391. // ret = "..."
  392. // name += ret
  393. // typ = typ[3:]
  394. // }
  395. // if strings.Contains(param.Type, "CodeInterface") {
  396. // params.Add(G.Id(param.Name).Op(ret).Qual(GENERATOR_BASE, typ))
  397. // } else {
  398. // params.Add(G.Id(param.Name).Id(typ))
  399. // }
  400. // paramsKeys = append(paramsKeys, name)
  401. // // params = append(params, G.Id(param.Name).Id(param.Type))
  402. // }
  403. // file.Func().Params(
  404. // G.Id("g").Op("*").Id("Group"),
  405. // ).Id(method).Params(*params...).Params(
  406. // G.Op("*").Id("Group"),
  407. // ).Block(
  408. // // G.Id("g").Dot(method).CallFunc(func(g *G.Group) {
  409. // // for _, key := range paramsKeys {
  410. // // g.Add(G.Id(key))
  411. // // }
  412. // // }),
  413. // G.Id("g").Dot("Group").Dot(method).CallFunc(func(g *G.Group) {
  414. // for _, key := range paramsKeys {
  415. // g.Add(G.Id(key))
  416. // }
  417. // }),
  418. // G.Return(G.Id("g")),
  419. // ).Line()
  420. // file.Func().Id(method).Params(*params...).Params(
  421. // G.Op("*").Id("Group"),
  422. // ).Block(
  423. // G.Return(G.Id("NewGroup").Call().Dot(method).CallFunc(func(g *G.Group) {
  424. // for _, key := range paramsKeys {
  425. // g.Add(G.Id(key))
  426. // }
  427. // })),
  428. // ).Line()
  429. // }
  430. // }