prettyprinter.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * Public Domain Software
  3. *
  4. * I (Matthias Ladkau) am the author of the source code in this file.
  5. * I have placed the source code in this file in the public domain.
  6. *
  7. * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
  8. */
  9. package parser
  10. import (
  11. "bytes"
  12. "fmt"
  13. "strconv"
  14. "text/template"
  15. "devt.de/krotik/common/errorutil"
  16. "devt.de/krotik/common/stringutil"
  17. )
  18. /*
  19. Map of AST nodes corresponding to lexer tokens
  20. */
  21. var prettyPrinterMap map[string]*template.Template
  22. /*
  23. Map of nodes where the precedence might have changed because of parentheses
  24. */
  25. var bracketPrecedenceMap map[string]bool
  26. func init() {
  27. prettyPrinterMap = map[string]*template.Template{
  28. NodeSTRING: template.Must(template.New(NodeSTRING).Parse("{{.qval}}")),
  29. NodeNUMBER: template.Must(template.New(NodeNUMBER).Parse("{{.val}}")),
  30. // NodeIDENTIFIER - Special case (handled in code)
  31. // Constructed tokens
  32. // NodeSTATEMENTS - Special case (handled in code)
  33. // NodeFUNCCALL - Special case (handled in code)
  34. NodeCOMPACCESS + "_1": template.Must(template.New(NodeCOMPACCESS).Parse("[{{.c1}}]")),
  35. /*
  36. NodeSTATEMENTS = "statements" // List of statements
  37. // Assignment statement
  38. NodeASSIGN = ":="
  39. */
  40. // Assignment statement
  41. NodeASSIGN + "_2": template.Must(template.New(NodeMINUS).Parse("{{.c1}} := {{.c2}}")),
  42. // Import statement
  43. NodeIMPORT + "_2": template.Must(template.New(NodeMINUS).Parse("import {{.c1}} as {{.c2}}")),
  44. // Arithmetic operators
  45. NodePLUS + "_1": template.Must(template.New(NodePLUS).Parse("+{{.c1}}")),
  46. NodePLUS + "_2": template.Must(template.New(NodePLUS).Parse("{{.c1}} + {{.c2}}")),
  47. NodeMINUS + "_1": template.Must(template.New(NodeMINUS).Parse("-{{.c1}}")),
  48. NodeMINUS + "_2": template.Must(template.New(NodeMINUS).Parse("{{.c1}} - {{.c2}}")),
  49. NodeTIMES + "_2": template.Must(template.New(NodeTIMES).Parse("{{.c1}} * {{.c2}}")),
  50. NodeDIV + "_2": template.Must(template.New(NodeDIV).Parse("{{.c1}} / {{.c2}}")),
  51. NodeMODINT + "_2": template.Must(template.New(NodeMODINT).Parse("{{.c1}} % {{.c2}}")),
  52. NodeDIVINT + "_2": template.Must(template.New(NodeDIVINT).Parse("{{.c1}} // {{.c2}}")),
  53. // Boolean operators
  54. NodeOR + "_2": template.Must(template.New(NodeGEQ).Parse("{{.c1}} or {{.c2}}")),
  55. NodeAND + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} and {{.c2}}")),
  56. NodeNOT + "_1": template.Must(template.New(NodeNOT).Parse("not {{.c1}}")),
  57. // Condition operators
  58. NodeLIKE + "_2": template.Must(template.New(NodeGEQ).Parse("{{.c1}} like {{.c2}}")),
  59. NodeIN + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} in {{.c2}}")),
  60. NodeHASPREFIX + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} hasprefix {{.c2}}")),
  61. NodeHASSUFFIX + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} hassuffix {{.c2}}")),
  62. NodeNOTIN + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} notin {{.c2}}")),
  63. NodeGEQ + "_2": template.Must(template.New(NodeGEQ).Parse("{{.c1}} >= {{.c2}}")),
  64. NodeLEQ + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} <= {{.c2}}")),
  65. NodeNEQ + "_2": template.Must(template.New(NodeNEQ).Parse("{{.c1}} != {{.c2}}")),
  66. NodeEQ + "_2": template.Must(template.New(NodeEQ).Parse("{{.c1}} == {{.c2}}")),
  67. NodeGT + "_2": template.Must(template.New(NodeGT).Parse("{{.c1}} > {{.c2}}")),
  68. NodeLT + "_2": template.Must(template.New(NodeLT).Parse("{{.c1}} < {{.c2}}")),
  69. // Separators
  70. NodeKVP + "_2": template.Must(template.New(NodeLT).Parse("{{.c1}} : {{.c2}}")),
  71. // Constants
  72. NodeTRUE: template.Must(template.New(NodeTRUE).Parse("true")),
  73. NodeFALSE: template.Must(template.New(NodeFALSE).Parse("false")),
  74. NodeNULL: template.Must(template.New(NodeNULL).Parse("null")),
  75. }
  76. bracketPrecedenceMap = map[string]bool{
  77. NodePLUS: true,
  78. NodeMINUS: true,
  79. NodeAND: true,
  80. NodeOR: true,
  81. }
  82. }
  83. /*
  84. PrettyPrint produces pretty printed code from a given AST.
  85. */
  86. func PrettyPrint(ast *ASTNode) (string, error) {
  87. var visit func(ast *ASTNode, level int) (string, error)
  88. ppMetaData := func(ast *ASTNode, ppString string) string {
  89. ret := ppString
  90. // Add meta data
  91. if len(ast.Meta) > 0 {
  92. for _, meta := range ast.Meta {
  93. if meta.Type() == MetaDataPreComment {
  94. ret = fmt.Sprintf("/*%v*/ %v", meta.Value(), ret)
  95. } else if meta.Type() == MetaDataPostComment {
  96. ret = fmt.Sprintf("%v #%v", ret, meta.Value())
  97. }
  98. }
  99. }
  100. return ret
  101. }
  102. visit = func(ast *ASTNode, level int) (string, error) {
  103. var buf bytes.Buffer
  104. var numChildren = len(ast.Children)
  105. tempKey := ast.Name
  106. tempParam := make(map[string]string)
  107. // First pretty print children
  108. if numChildren > 0 {
  109. for i, child := range ast.Children {
  110. res, err := visit(child, level+1)
  111. if err != nil {
  112. return "", err
  113. }
  114. if _, ok := bracketPrecedenceMap[child.Name]; ok && ast.binding > child.binding {
  115. // Put the expression in brackets iff (if and only if) the binding would
  116. // normally order things differently
  117. res = fmt.Sprintf("(%v)", res)
  118. }
  119. tempParam[fmt.Sprint("c", i+1)] = res
  120. }
  121. tempKey += fmt.Sprint("_", len(tempParam))
  122. }
  123. // Handle special cases - children in tempParam have been resolved
  124. if ast.Name == NodeSTATEMENTS {
  125. // For statements just concat all children
  126. for i := 0; i < numChildren; i++ {
  127. buf.WriteString(stringutil.GenerateRollingString(" ", level*4))
  128. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  129. buf.WriteString("\n")
  130. }
  131. return ppMetaData(ast, buf.String()), nil
  132. } else if ast.Name == NodeFUNCCALL {
  133. // For statements just concat all children
  134. for i := 0; i < numChildren; i++ {
  135. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  136. if i < numChildren-1 {
  137. buf.WriteString(", ")
  138. }
  139. }
  140. return ppMetaData(ast, buf.String()), nil
  141. } else if ast.Name == NodeIDENTIFIER {
  142. buf.WriteString(ast.Token.Val)
  143. for i := 0; i < numChildren; i++ {
  144. if ast.Children[i].Name == NodeIDENTIFIER {
  145. buf.WriteString(".")
  146. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  147. } else if ast.Children[i].Name == NodeFUNCCALL {
  148. buf.WriteString("(")
  149. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  150. buf.WriteString(")")
  151. } else if ast.Children[i].Name == NodeCOMPACCESS {
  152. buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
  153. }
  154. }
  155. return ppMetaData(ast, buf.String()), nil
  156. } else if ast.Name == NodeLIST {
  157. buf.WriteString("[")
  158. i := 1
  159. for ; i < numChildren; i++ {
  160. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  161. buf.WriteString(", ")
  162. }
  163. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  164. buf.WriteString("]")
  165. return ppMetaData(ast, buf.String()), nil
  166. } else if ast.Name == NodeMAP {
  167. buf.WriteString("{")
  168. i := 1
  169. for ; i < numChildren; i++ {
  170. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  171. buf.WriteString(", ")
  172. }
  173. buf.WriteString(tempParam[fmt.Sprint("c", i)])
  174. buf.WriteString("}")
  175. return ppMetaData(ast, buf.String()), nil
  176. }
  177. if ast.Token != nil {
  178. // Adding node value to template parameters
  179. tempParam["val"] = ast.Token.Val
  180. tempParam["qval"] = strconv.Quote(ast.Token.Val)
  181. }
  182. // Retrieve the template
  183. temp, ok := prettyPrinterMap[tempKey]
  184. if !ok {
  185. return "", fmt.Errorf("Could not find template for %v (tempkey: %v)",
  186. ast.Name, tempKey)
  187. }
  188. // Use the children as parameters for template
  189. errorutil.AssertOk(temp.Execute(&buf, tempParam))
  190. return ppMetaData(ast, buf.String()), nil
  191. }
  192. return visit(ast, 0)
  193. }