prettyprinter.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package parser
  11. import (
  12. "bytes"
  13. "fmt"
  14. "strconv"
  15. "text/template"
  16. "devt.de/krotik/common/errorutil"
  17. "devt.de/krotik/common/stringutil"
  18. )
  19. /*
  20. Map of AST nodes corresponding to lexer tokens
  21. */
  22. var prettyPrinterMap map[string]*template.Template
  23. /*
  24. Map of nodes where the precedence might have changed because of parentheses
  25. */
  26. var bracketPrecedenceMap map[string]bool
  27. func init() {
  28. prettyPrinterMap = map[string]*template.Template{
  29. NodeSTRING: template.Must(template.New(NodeSTRING).Parse("{{.qval}}")),
  30. NodeNUMBER: template.Must(template.New(NodeNUMBER).Parse("{{.val}}")),
  31. // NodeIDENTIFIER - Special case (handled in code)
  32. // Constructed tokens
  33. // NodeSTATEMENTS - Special case (handled in code)
  34. // NodeFUNCCALL - Special case (handled in code)
  35. NodeCOMPACCESS + "_1": template.Must(template.New(NodeCOMPACCESS).Parse("[{{.c1}}]")),
  36. // TokenLIST - Special case (handled in code)
  37. // TokenMAP - Special case (handled in code)
  38. // TokenPARAMS - Special case (handled in code)
  39. NodeGUARD + "_1": template.Must(template.New(NodeGUARD).Parse("{{.c1}}")),
  40. // Condition operators
  41. NodeGEQ + "_2": template.Must(template.New(NodeGEQ).Parse("{{.c1}} >= {{.c2}}")),
  42. NodeLEQ + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} <= {{.c2}}")),
  43. NodeNEQ + "_2": template.Must(template.New(NodeNEQ).Parse("{{.c1}} != {{.c2}}")),
  44. NodeEQ + "_2": template.Must(template.New(NodeEQ).Parse("{{.c1}} == {{.c2}}")),
  45. NodeGT + "_2": template.Must(template.New(NodeGT).Parse("{{.c1}} > {{.c2}}")),
  46. NodeLT + "_2": template.Must(template.New(NodeLT).Parse("{{.c1}} < {{.c2}}")),
  47. // Separators
  48. NodeKVP + "_2": template.Must(template.New(NodeKVP).Parse("{{.c1}} : {{.c2}}")),
  49. NodePRESET + "_2": template.Must(template.New(NodePRESET).Parse("{{.c1}}={{.c2}}")),
  50. // Arithmetic operators
  51. NodePLUS + "_1": template.Must(template.New(NodePLUS).Parse("+{{.c1}}")),
  52. NodePLUS + "_2": template.Must(template.New(NodePLUS).Parse("{{.c1}} + {{.c2}}")),
  53. NodeMINUS + "_1": template.Must(template.New(NodeMINUS).Parse("-{{.c1}}")),
  54. NodeMINUS + "_2": template.Must(template.New(NodeMINUS).Parse("{{.c1}} - {{.c2}}")),
  55. NodeTIMES + "_2": template.Must(template.New(NodeTIMES).Parse("{{.c1}} * {{.c2}}")),
  56. NodeDIV + "_2": template.Must(template.New(NodeDIV).Parse("{{.c1}} / {{.c2}}")),
  57. NodeMODINT + "_2": template.Must(template.New(NodeMODINT).Parse("{{.c1}} % {{.c2}}")),
  58. NodeDIVINT + "_2": template.Must(template.New(NodeDIVINT).Parse("{{.c1}} // {{.c2}}")),
  59. // Assignment statement
  60. NodeASSIGN + "_2": template.Must(template.New(NodeASSIGN).Parse("{{.c1}} := {{.c2}}")),
  61. NodeLET + "_1": template.Must(template.New(NodeASSIGN).Parse("let {{.c1}}")),
  62. // Import statement
  63. NodeIMPORT + "_2": template.Must(template.New(NodeIMPORT).Parse("import {{.c1}} as {{.c2}}")),
  64. NodeAS + "_1": template.Must(template.New(NodeRETURN).Parse("as {{.c1}}")),
  65. // Sink definition
  66. // NodeSINK - Special case (handled in code)
  67. NodeKINDMATCH + "_1": template.Must(template.New(NodeKINDMATCH).Parse("kindmatch {{.c1}}")),
  68. NodeSCOPEMATCH + "_1": template.Must(template.New(NodeSCOPEMATCH).Parse("scopematch {{.c1}}")),
  69. NodeSTATEMATCH + "_1": template.Must(template.New(NodeSTATEMATCH).Parse("statematch {{.c1}}")),
  70. NodePRIORITY + "_1": template.Must(template.New(NodePRIORITY).Parse("priority {{.c1}}")),
  71. NodeSUPPRESSES + "_1": template.Must(template.New(NodeSUPPRESSES).Parse("suppresses {{.c1}}")),
  72. // Function definition
  73. NodeFUNC + "_2": template.Must(template.New(NodeFUNC).Parse("func {{.c1}} {\n{{.c2}}}")),
  74. NodeFUNC + "_3": template.Must(template.New(NodeFUNC).Parse("func {{.c1}}{{.c2}} {\n{{.c3}}}")),
  75. NodeRETURN: template.Must(template.New(NodeRETURN).Parse("return")),
  76. NodeRETURN + "_1": template.Must(template.New(NodeRETURN).Parse("return {{.c1}}")),
  77. // Boolean operators
  78. NodeOR + "_2": template.Must(template.New(NodeOR).Parse("{{.c1}} or {{.c2}}")),
  79. NodeAND + "_2": template.Must(template.New(NodeAND).Parse("{{.c1}} and {{.c2}}")),
  80. NodeNOT + "_1": template.Must(template.New(NodeNOT).Parse("not {{.c1}}")),
  81. // Condition operators
  82. NodeLIKE + "_2": template.Must(template.New(NodeLIKE).Parse("{{.c1}} like {{.c2}}")),
  83. NodeIN + "_2": template.Must(template.New(NodeIN).Parse("{{.c1}} in {{.c2}}")),
  84. NodeHASPREFIX + "_2": template.Must(template.New(NodeHASPREFIX).Parse("{{.c1}} hasprefix {{.c2}}")),
  85. NodeHASSUFFIX + "_2": template.Must(template.New(NodeHASSUFFIX).Parse("{{.c1}} hassuffix {{.c2}}")),
  86. NodeNOTIN + "_2": template.Must(template.New(NodeNOTIN).Parse("{{.c1}} notin {{.c2}}")),
  87. // Constant terminals
  88. NodeTRUE: template.Must(template.New(NodeTRUE).Parse("true")),
  89. NodeFALSE: template.Must(template.New(NodeFALSE).Parse("false")),
  90. NodeNULL: template.Must(template.New(NodeNULL).Parse("null")),
  91. // Conditional statements
  92. // TokenIF - Special case (handled in code)
  93. // TokenELIF - Special case (handled in code)
  94. // TokenELSE - Special case (handled in code)
  95. // Loop statement
  96. NodeLOOP + "_2": template.Must(template.New(NodeLOOP).Parse("for {{.c1}} {\n{{.c2}}}\n")),
  97. NodeBREAK: template.Must(template.New(NodeBREAK).Parse("break")),
  98. NodeCONTINUE: template.Must(template.New(NodeCONTINUE).Parse("continue")),
  99. // Try statement
  100. // TokenTRY - Special case (handled in code)
  101. // TokenEXCEPT - Special case (handled in code)
  102. NodeFINALLY + "_1": template.Must(template.New(NodeFINALLY).Parse(" finally {\n{{.c1}}}\n")),
  103. // Mutex block
  104. NodeMUTEX + "_2": template.Must(template.New(NodeLOOP).Parse("mutex {{.c1}} {\n{{.c2}}}\n")),
  105. }
  106. bracketPrecedenceMap = map[string]bool{
  107. NodePLUS: true,
  108. NodeMINUS: true,
  109. NodeAND: true,
  110. NodeOR: true,
  111. }
  112. }
  113. /*
  114. PrettyPrint produces pretty printed code from a given AST.
  115. */
  116. func PrettyPrint(ast *ASTNode) (string, error) {
  117. var visit func(ast *ASTNode, level int) (string, error)
  118. visit = func(ast *ASTNode, level int) (string, error) {
  119. var buf bytes.Buffer
  120. if ast == nil {
  121. return "", fmt.Errorf("Nil pointer in AST at level: %v", level)
  122. }
  123. numChildren := len(ast.Children)
  124. tempKey := ast.Name
  125. tempParam := make(map[string]string)
  126. // First pretty print children
  127. if numChildren > 0 {
  128. for i, child := range ast.Children {
  129. res, err := visit(child, level+1)
  130. if err != nil {
  131. return "", err
  132. }
  133. if _, ok := bracketPrecedenceMap[child.Name]; ok && ast.binding > child.binding {
  134. // Put the expression in brackets iff (if and only if) the binding would
  135. // normally order things differently
  136. res = fmt.Sprintf("(%v)", res)
  137. }
  138. tempParam[fmt.Sprint("c", i+1)] = res
  139. }
  140. tempKey += fmt.Sprint("_", len(tempParam))
  141. }
  142. if res, ok := ppSpecialDefs(ast, level, tempParam, &buf); ok {
  143. return res, nil
  144. } else if res, ok := ppSpecialBlocks(ast, level, tempParam, &buf); ok {
  145. return res, nil
  146. } else if res, ok := ppSpecialStatements(ast, level, tempParam, &buf); ok {
  147. return res, nil
  148. }
  149. if ast.Token != nil {
  150. // Adding node value to template parameters
  151. tempParam["val"] = ast.Token.Val
  152. tempParam["qval"] = strconv.Quote(ast.Token.Val)
  153. }
  154. // Retrieve the template
  155. temp, ok := prettyPrinterMap[tempKey]
  156. errorutil.AssertTrue(ok,
  157. fmt.Sprintf("Could not find template for %v (tempkey: %v)",
  158. ast.Name, tempKey))
  159. // Use the children as parameters for template
  160. errorutil.AssertOk(temp.Execute(&buf, tempParam))
  161. return ppMetaData(ast, buf.String()), nil
  162. }
  163. return visit(ast, 0)
  164. }
  165. /*
  166. ppMetaData pretty prints meta data.
  167. */
  168. func ppMetaData(ast *ASTNode, ppString string) string {
  169. ret := ppString
  170. // Add meta data
  171. if len(ast.Meta) > 0 {
  172. for _, meta := range ast.Meta {
  173. if meta.Type() == MetaDataPreComment {
  174. ret = fmt.Sprintf("/*%v*/ %v", meta.Value(), ret)
  175. } else if meta.Type() == MetaDataPostComment {
  176. ret = fmt.Sprintf("%v #%v", ret, meta.Value())
  177. }
  178. }
  179. }
  180. return ret
  181. }
  182. /*
  183. ppSpecialDefs pretty prints special cases.
  184. */
  185. func ppSpecialDefs(ast *ASTNode, level int, tempParam map[string]string, buf *bytes.Buffer) (string, bool) {
  186. numChildren := len(ast.Children)
  187. if ast.Name == NodeFUNCCALL {
  188. for i := 0; i < numChildren; i++ {
  189. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  190. if i < numChildren-1 {
  191. buf.WriteString(", ")
  192. }
  193. }
  194. return ppMetaData(ast, buf.String()), true
  195. } else if ast.Name == NodeSINK {
  196. buf.WriteString("sink ")
  197. buf.WriteString(tempParam["c1"])
  198. buf.WriteString("\n")
  199. for i := 1; i < len(ast.Children)-1; i++ {
  200. buf.WriteString(" ")
  201. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  202. buf.WriteString("\n")
  203. }
  204. buf.WriteString("{\n")
  205. buf.WriteString(tempParam[fmt.Sprint("c", len(ast.Children))])
  206. buf.WriteString("}\n")
  207. return ppMetaData(ast, buf.String()), true
  208. }
  209. return "", false
  210. }
  211. /*
  212. ppSpecialBlocks pretty prints special cases.
  213. */
  214. func ppSpecialBlocks(ast *ASTNode, level int, tempParam map[string]string, buf *bytes.Buffer) (string, bool) {
  215. numChildren := len(ast.Children)
  216. // Handle special cases - children in tempParam have been resolved
  217. if stringutil.IndexOf(ast.Name, []string{NodeSTATEMENTS}) != -1 {
  218. // For statements just concat all children
  219. for i := 0; i < numChildren; i++ {
  220. buf.WriteString(stringutil.GenerateRollingString(" ", level*4))
  221. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  222. buf.WriteString("\n")
  223. }
  224. return ppMetaData(ast, buf.String()), true
  225. } else if ast.Name == NodeLIST {
  226. buf.WriteString("[")
  227. i := 1
  228. for ; i < numChildren; i++ {
  229. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  230. buf.WriteString(", ")
  231. }
  232. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  233. buf.WriteString("]")
  234. return ppMetaData(ast, buf.String()), true
  235. } else if ast.Name == NodeMAP {
  236. buf.WriteString("{")
  237. i := 1
  238. for ; i < numChildren; i++ {
  239. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  240. buf.WriteString(", ")
  241. }
  242. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  243. buf.WriteString("}")
  244. return ppMetaData(ast, buf.String()), true
  245. } else if ast.Name == NodeTRY {
  246. buf.WriteString("try {\n")
  247. buf.WriteString(tempParam[fmt.Sprint("c1")])
  248. buf.WriteString("}")
  249. for i := 1; i < len(ast.Children); i++ {
  250. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  251. }
  252. buf.WriteString("\n")
  253. return ppMetaData(ast, buf.String()), true
  254. } else if ast.Name == NodeEXCEPT {
  255. buf.WriteString(" except ")
  256. for i := 0; i < len(ast.Children)-1; i++ {
  257. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  258. if ast.Children[i+1].Name != NodeAS && i < len(ast.Children)-2 {
  259. buf.WriteString(",")
  260. }
  261. buf.WriteString(" ")
  262. }
  263. buf.WriteString("{\n")
  264. buf.WriteString(tempParam[fmt.Sprint("c", len(ast.Children))])
  265. buf.WriteString("}")
  266. return ppMetaData(ast, buf.String()), true
  267. }
  268. return "", false
  269. }
  270. /*
  271. ppSpecialStatements pretty prints special cases.
  272. */
  273. func ppSpecialStatements(ast *ASTNode, level int, tempParam map[string]string, buf *bytes.Buffer) (string, bool) {
  274. numChildren := len(ast.Children)
  275. if ast.Name == NodeIDENTIFIER {
  276. buf.WriteString(ast.Token.Val)
  277. for i := 0; i < numChildren; i++ {
  278. if ast.Children[i].Name == NodeIDENTIFIER {
  279. buf.WriteString(".")
  280. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  281. } else if ast.Children[i].Name == NodeFUNCCALL {
  282. buf.WriteString("(")
  283. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  284. buf.WriteString(")")
  285. } else if ast.Children[i].Name == NodeCOMPACCESS {
  286. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  287. }
  288. }
  289. return ppMetaData(ast, buf.String()), true
  290. } else if ast.Name == NodePARAMS {
  291. buf.WriteString("(")
  292. i := 1
  293. for ; i < numChildren; i++ {
  294. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  295. buf.WriteString(", ")
  296. }
  297. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  298. buf.WriteString(")")
  299. return ppMetaData(ast, buf.String()), true
  300. } else if ast.Name == NodeIF {
  301. writeGUARD := func(child int) {
  302. buf.WriteString(tempParam[fmt.Sprint("c", child)])
  303. buf.WriteString(" {\n")
  304. buf.WriteString(tempParam[fmt.Sprint("c", child+1)])
  305. buf.WriteString("}")
  306. }
  307. buf.WriteString("if ")
  308. writeGUARD(1)
  309. for i := 0; i < len(ast.Children); i += 2 {
  310. if i+2 == len(ast.Children) && ast.Children[i].Children[0].Name == NodeTRUE {
  311. buf.WriteString(" else {\n")
  312. buf.WriteString(tempParam[fmt.Sprint("c", i+2)])
  313. buf.WriteString("}")
  314. } else if i > 0 {
  315. buf.WriteString(" elif ")
  316. writeGUARD(i + 1)
  317. }
  318. }
  319. buf.WriteString("\n")
  320. return ppMetaData(ast, buf.String()), true
  321. }
  322. return "", false
  323. }