template.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package pongo2
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. )
  7. type Template struct {
  8. set *TemplateSet
  9. // Input
  10. is_tpl_string bool
  11. name string
  12. tpl string
  13. size int
  14. // Calculation
  15. tokens []*Token
  16. parser *Parser
  17. // first come, first serve (it's important to not override existing entries in here)
  18. level int
  19. parent *Template
  20. child *Template
  21. blocks map[string]*NodeWrapper
  22. exported_macros map[string]*tagMacroNode
  23. // Output
  24. root *nodeDocument
  25. }
  26. func newTemplateString(set *TemplateSet, tpl string) (*Template, error) {
  27. return newTemplate(set, "<string>", true, tpl)
  28. }
  29. func newTemplate(set *TemplateSet, name string, is_tpl_string bool, tpl string) (*Template, error) {
  30. // Create the template
  31. t := &Template{
  32. set: set,
  33. is_tpl_string: is_tpl_string,
  34. name: name,
  35. tpl: tpl,
  36. size: len(tpl),
  37. blocks: make(map[string]*NodeWrapper),
  38. exported_macros: make(map[string]*tagMacroNode),
  39. }
  40. // Tokenize it
  41. tokens, err := lex(name, tpl)
  42. if err != nil {
  43. return nil, err
  44. }
  45. t.tokens = tokens
  46. // For debugging purposes, show all tokens:
  47. /*for i, t := range tokens {
  48. fmt.Printf("%3d. %s\n", i, t)
  49. }*/
  50. // Parse it
  51. err = t.parse()
  52. if err != nil {
  53. return nil, err
  54. }
  55. return t, nil
  56. }
  57. func (tpl *Template) execute(context Context) (*bytes.Buffer, error) {
  58. // Create output buffer
  59. // We assume that the rendered template will be 30% larger
  60. buffer := bytes.NewBuffer(make([]byte, 0, int(float64(tpl.size)*1.3)))
  61. // Determine the parent to be executed (for template inheritance)
  62. parent := tpl
  63. for parent.parent != nil {
  64. parent = parent.parent
  65. }
  66. // Create context if none is given
  67. newContext := make(Context)
  68. newContext.Update(tpl.set.Globals)
  69. if context != nil {
  70. newContext.Update(context)
  71. if len(newContext) > 0 {
  72. // Check for context name syntax
  73. err := newContext.checkForValidIdentifiers()
  74. if err != nil {
  75. return nil, err
  76. }
  77. // Check for clashes with macro names
  78. for k, _ := range newContext {
  79. _, has := tpl.exported_macros[k]
  80. if has {
  81. return nil, &Error{
  82. Filename: tpl.name,
  83. Sender: "execution",
  84. ErrorMsg: fmt.Sprintf("Context key name '%s' clashes with macro '%s'.", k, k),
  85. }
  86. }
  87. }
  88. }
  89. }
  90. // Create operational context
  91. ctx := newExecutionContext(parent, newContext)
  92. // Run the selected document
  93. err := parent.root.Execute(ctx, buffer)
  94. if err != nil {
  95. return nil, err
  96. }
  97. return buffer, nil
  98. }
  99. // Executes the template with the given context and writes to writer (io.Writer)
  100. // on success. Context can be nil. Nothing is written on error; instead the error
  101. // is being returned.
  102. func (tpl *Template) ExecuteWriter(context Context, writer io.Writer) error {
  103. buffer, err := tpl.execute(context)
  104. if err != nil {
  105. return err
  106. }
  107. l := buffer.Len()
  108. n, werr := buffer.WriteTo(writer)
  109. if int(n) != l {
  110. panic(fmt.Sprintf("error on writing template: n(%d) != buffer.Len(%d)", n, l))
  111. }
  112. if werr != nil {
  113. return &Error{
  114. Filename: tpl.name,
  115. Sender: "execution",
  116. ErrorMsg: werr.Error(),
  117. }
  118. }
  119. return nil
  120. }
  121. // Executes the template and returns the rendered template as a []byte
  122. func (tpl *Template) ExecuteBytes(context Context) ([]byte, error) {
  123. // Execute template
  124. buffer, err := tpl.execute(context)
  125. if err != nil {
  126. return nil, err
  127. }
  128. return buffer.Bytes(), nil
  129. }
  130. // Executes the template and returns the rendered template as a string
  131. func (tpl *Template) Execute(context Context) (string, error) {
  132. // Execute template
  133. buffer, err := tpl.execute(context)
  134. if err != nil {
  135. return "", err
  136. }
  137. return buffer.String(), nil
  138. }