template.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package pongo2
  2. import (
  3. "bytes"
  4. "io"
  5. "github.com/juju/errors"
  6. )
  7. type TemplateWriter interface {
  8. io.Writer
  9. WriteString(string) (int, error)
  10. }
  11. type templateWriter struct {
  12. w io.Writer
  13. }
  14. func (tw *templateWriter) WriteString(s string) (int, error) {
  15. return tw.w.Write([]byte(s))
  16. }
  17. func (tw *templateWriter) Write(b []byte) (int, error) {
  18. return tw.w.Write(b)
  19. }
  20. type Template struct {
  21. set *TemplateSet
  22. // Input
  23. isTplString bool
  24. name string
  25. tpl string
  26. size int
  27. // Calculation
  28. tokens []*Token
  29. parser *Parser
  30. // first come, first serve (it's important to not override existing entries in here)
  31. level int
  32. parent *Template
  33. child *Template
  34. blocks map[string]*NodeWrapper
  35. exportedMacros map[string]*tagMacroNode
  36. // Output
  37. root *nodeDocument
  38. }
  39. func newTemplateString(set *TemplateSet, tpl []byte) (*Template, error) {
  40. return newTemplate(set, "<string>", true, tpl)
  41. }
  42. func newTemplate(set *TemplateSet, name string, isTplString bool, tpl []byte) (*Template, error) {
  43. strTpl := string(tpl)
  44. // Create the template
  45. t := &Template{
  46. set: set,
  47. isTplString: isTplString,
  48. name: name,
  49. tpl: strTpl,
  50. size: len(strTpl),
  51. blocks: make(map[string]*NodeWrapper),
  52. exportedMacros: make(map[string]*tagMacroNode),
  53. }
  54. // Tokenize it
  55. tokens, err := lex(name, strTpl)
  56. if err != nil {
  57. return nil, err
  58. }
  59. t.tokens = tokens
  60. // For debugging purposes, show all tokens:
  61. /*for i, t := range tokens {
  62. fmt.Printf("%3d. %s\n", i, t)
  63. }*/
  64. // Parse it
  65. err = t.parse()
  66. if err != nil {
  67. return nil, err
  68. }
  69. return t, nil
  70. }
  71. func (tpl *Template) execute(context Context, writer TemplateWriter) error {
  72. // Determine the parent to be executed (for template inheritance)
  73. parent := tpl
  74. for parent.parent != nil {
  75. parent = parent.parent
  76. }
  77. // Create context if none is given
  78. newContext := make(Context)
  79. newContext.Update(tpl.set.Globals)
  80. if context != nil {
  81. newContext.Update(context)
  82. if len(newContext) > 0 {
  83. // Check for context name syntax
  84. err := newContext.checkForValidIdentifiers()
  85. if err != nil {
  86. return err
  87. }
  88. // Check for clashes with macro names
  89. for k := range newContext {
  90. _, has := tpl.exportedMacros[k]
  91. if has {
  92. return &Error{
  93. Filename: tpl.name,
  94. Sender: "execution",
  95. OrigError: errors.Errorf("context key name '%s' clashes with macro '%s'", k, k),
  96. }
  97. }
  98. }
  99. }
  100. }
  101. // Create operational context
  102. ctx := newExecutionContext(parent, newContext)
  103. // Run the selected document
  104. if err := parent.root.Execute(ctx, writer); err != nil {
  105. return err
  106. }
  107. return nil
  108. }
  109. func (tpl *Template) newTemplateWriterAndExecute(context Context, writer io.Writer) error {
  110. return tpl.execute(context, &templateWriter{w: writer})
  111. }
  112. func (tpl *Template) newBufferAndExecute(context Context) (*bytes.Buffer, error) {
  113. // Create output buffer
  114. // We assume that the rendered template will be 30% larger
  115. buffer := bytes.NewBuffer(make([]byte, 0, int(float64(tpl.size)*1.3)))
  116. if err := tpl.execute(context, buffer); err != nil {
  117. return nil, err
  118. }
  119. return buffer, nil
  120. }
  121. // Executes the template with the given context and writes to writer (io.Writer)
  122. // on success. Context can be nil. Nothing is written on error; instead the error
  123. // is being returned.
  124. func (tpl *Template) ExecuteWriter(context Context, writer io.Writer) error {
  125. buf, err := tpl.newBufferAndExecute(context)
  126. if err != nil {
  127. return err
  128. }
  129. _, err = buf.WriteTo(writer)
  130. if err != nil {
  131. return err
  132. }
  133. return nil
  134. }
  135. // Same as ExecuteWriter. The only difference between both functions is that
  136. // this function might already have written parts of the generated template in the
  137. // case of an execution error because there's no intermediate buffer involved for
  138. // performance reasons. This is handy if you need high performance template
  139. // generation or if you want to manage your own pool of buffers.
  140. func (tpl *Template) ExecuteWriterUnbuffered(context Context, writer io.Writer) error {
  141. return tpl.newTemplateWriterAndExecute(context, writer)
  142. }
  143. // Executes the template and returns the rendered template as a []byte
  144. func (tpl *Template) ExecuteBytes(context Context) ([]byte, error) {
  145. // Execute template
  146. buffer, err := tpl.newBufferAndExecute(context)
  147. if err != nil {
  148. return nil, err
  149. }
  150. return buffer.Bytes(), nil
  151. }
  152. // Executes the template and returns the rendered template as a string
  153. func (tpl *Template) Execute(context Context) (string, error) {
  154. // Execute template
  155. buffer, err := tpl.newBufferAndExecute(context)
  156. if err != nil {
  157. return "", err
  158. }
  159. return buffer.String(), nil
  160. }