prettyprinter.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. )
  17. /*
  18. Map of AST nodes corresponding to lexer tokens
  19. */
  20. var prettyPrinterMap map[string]*template.Template
  21. /*
  22. Map of nodes where the precedence might have changed because of parentheses
  23. */
  24. var bracketPrecedenceMap map[string]bool
  25. func init() {
  26. prettyPrinterMap = map[string]*template.Template{
  27. NodeCOMMENT: template.Must(template.New(NodeTRUE).Parse("true")),
  28. NodeSTRING: template.Must(template.New(NodeTRUE).Parse("{{.qval}}")),
  29. NodeNUMBER: template.Must(template.New(NodeTRUE).Parse("{{.val}}")),
  30. NodeIDENTIFIER: template.Must(template.New(NodeTRUE).Parse("{{.val}}")),
  31. /*
  32. // Constructed tokens
  33. NodeSTATEMENTS = "statements" // List of statements
  34. // Assignment statement
  35. NodeASSIGN = ":="
  36. */
  37. // Arithmetic operators
  38. NodePLUS + "_1": template.Must(template.New(NodeMINUS).Parse("+{{.c1}}")),
  39. NodePLUS + "_2": template.Must(template.New(NodePLUS).Parse("{{.c1}} + {{.c2}}")),
  40. NodeMINUS + "_1": template.Must(template.New(NodeMINUS).Parse("-{{.c1}}")),
  41. NodeMINUS + "_2": template.Must(template.New(NodeMINUS).Parse("{{.c1}} - {{.c2}}")),
  42. NodeTIMES + "_2": template.Must(template.New(NodeTIMES).Parse("{{.c1}} * {{.c2}}")),
  43. NodeDIV + "_2": template.Must(template.New(NodeDIV).Parse("{{.c1}} / {{.c2}}")),
  44. NodeMODINT + "_2": template.Must(template.New(NodeMODINT).Parse("{{.c1}} % {{.c2}}")),
  45. NodeDIVINT + "_2": template.Must(template.New(NodeDIVINT).Parse("{{.c1}} // {{.c2}}")),
  46. // Boolean operators
  47. NodeOR + "_2": template.Must(template.New(NodeGEQ).Parse("{{.c1}} or {{.c2}}")),
  48. NodeAND + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} and {{.c2}}")),
  49. NodeNOT + "_1": template.Must(template.New(NodeNOT).Parse("not {{.c1}}")),
  50. // Condition operators
  51. NodeLIKE + "_2": template.Must(template.New(NodeGEQ).Parse("{{.c1}} like {{.c2}}")),
  52. NodeIN + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} in {{.c2}}")),
  53. NodeHASPREFIX + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} hasprefix {{.c2}}")),
  54. NodeHASSUFFIX + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} hassuffix {{.c2}}")),
  55. NodeNOTIN + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} notin {{.c2}}")),
  56. NodeGEQ + "_2": template.Must(template.New(NodeGEQ).Parse("{{.c1}} >= {{.c2}}")),
  57. NodeLEQ + "_2": template.Must(template.New(NodeLEQ).Parse("{{.c1}} <= {{.c2}}")),
  58. NodeNEQ + "_2": template.Must(template.New(NodeNEQ).Parse("{{.c1}} != {{.c2}}")),
  59. NodeEQ + "_2": template.Must(template.New(NodeEQ).Parse("{{.c1}} == {{.c2}}")),
  60. NodeGT + "_2": template.Must(template.New(NodeGT).Parse("{{.c1}} > {{.c2}}")),
  61. NodeLT + "_2": template.Must(template.New(NodeLT).Parse("{{.c1}} < {{.c2}}")),
  62. // Constants
  63. NodeTRUE: template.Must(template.New(NodeTRUE).Parse("true")),
  64. NodeFALSE: template.Must(template.New(NodeFALSE).Parse("false")),
  65. NodeNULL: template.Must(template.New(NodeNULL).Parse("null")),
  66. }
  67. bracketPrecedenceMap = map[string]bool{
  68. NodePLUS: true,
  69. NodeMINUS: true,
  70. NodeAND: true,
  71. NodeOR: true,
  72. }
  73. }
  74. /*
  75. PrettyPrint produces pretty printed code from a given AST.
  76. */
  77. func PrettyPrint(ast *ASTNode) (string, error) {
  78. var visit func(ast *ASTNode, level int) (string, error)
  79. visit = func(ast *ASTNode, level int) (string, error) {
  80. var buf bytes.Buffer
  81. tempKey := ast.Name
  82. tempParam := make(map[string]string)
  83. // First pretty print children
  84. if len(ast.Children) > 0 {
  85. for i, child := range ast.Children {
  86. res, err := visit(child, level+1)
  87. if err != nil {
  88. return "", err
  89. }
  90. if _, ok := bracketPrecedenceMap[child.Name]; ok && ast.binding > child.binding {
  91. // Put the expression in brackets iff (if and only if) the binding would
  92. // normally order things differently
  93. res = fmt.Sprintf("(%v)", res)
  94. }
  95. tempParam[fmt.Sprint("c", i+1)] = res
  96. }
  97. tempKey += fmt.Sprint("_", len(tempParam))
  98. }
  99. // Adding node value to template parameters
  100. tempParam["val"] = ast.Token.Val
  101. tempParam["qval"] = strconv.Quote(ast.Token.Val)
  102. // Retrieve the template
  103. temp, ok := prettyPrinterMap[tempKey]
  104. if !ok {
  105. return "", fmt.Errorf("Could not find template for %v (tempkey: %v)",
  106. ast.Name, tempKey)
  107. }
  108. // Use the children as parameters for template
  109. errorutil.AssertOk(temp.Execute(&buf, tempParam))
  110. return buf.String(), nil
  111. }
  112. return visit(ast, 0)
  113. }