parse.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package jade
  5. import (
  6. "fmt"
  7. "io/ioutil"
  8. "runtime"
  9. )
  10. // Tree is the representation of a single parsed template.
  11. type Tree struct {
  12. Name string // name of the template represented by the tree.
  13. // ReadFunc is used to read files that are required when parsing a template (e.g. extends $file).
  14. // Set to a custom reader to override the default behavior from reading by system directory.
  15. //
  16. // See https://github.com/kataras/iris/issues/1450.
  17. ReadFunc func(path string) ([]byte, error)
  18. Root *ListNode // top-level root of the tree.
  19. text string // text parsed to create the template (or its parent)
  20. // Parsing only; cleared after parse.
  21. lex *lexer
  22. token [3]item // three-token lookahead for parser.
  23. peekCount int
  24. mixin map[string]*MixinNode
  25. block map[string]*ListNode
  26. }
  27. // Copy returns a copy of the Tree. Any parsing state is discarded.
  28. func (t *Tree) Copy() *Tree {
  29. if t == nil {
  30. return nil
  31. }
  32. return &Tree{
  33. Name: t.Name,
  34. ReadFunc: t.ReadFunc,
  35. Root: t.Root.CopyList(),
  36. text: t.text,
  37. }
  38. }
  39. // next returns the next token.
  40. func (t *Tree) next() item {
  41. if t.peekCount > 0 {
  42. t.peekCount--
  43. } else {
  44. t.token[0] = t.lex.nextItem()
  45. }
  46. return t.token[t.peekCount]
  47. }
  48. // backup backs the input stream up one token.
  49. func (t *Tree) backup() {
  50. t.peekCount++
  51. }
  52. // backup2 backs the input stream up two tokens.
  53. // The zeroth token is already there.
  54. func (t *Tree) backup2(t1 item) {
  55. t.token[1] = t1
  56. t.peekCount = 2
  57. }
  58. // backup3 backs the input stream up three tokens
  59. // The zeroth token is already there.
  60. func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back.
  61. t.token[1] = t1
  62. t.token[2] = t2
  63. t.peekCount = 3
  64. }
  65. // peek returns but does not consume the next token.
  66. func (t *Tree) peek() item {
  67. if t.peekCount > 0 {
  68. return t.token[t.peekCount-1]
  69. }
  70. t.peekCount = 1
  71. t.token[0] = t.lex.nextItem()
  72. return t.token[0]
  73. }
  74. // nextNonSpace returns the next non-space token.
  75. func (t *Tree) nextNonSpace() (token item) {
  76. for {
  77. token = t.next()
  78. if token.typ != itemIdent && token.typ != itemEndL && token.typ != itemEmptyLine {
  79. break
  80. }
  81. }
  82. // fmt.Println("\t\tnextNonSpace", token.val)
  83. return token
  84. }
  85. // peekNonSpace returns but does not consume the next non-space token.
  86. func (t *Tree) peekNonSpace() (token item) {
  87. for {
  88. token = t.next()
  89. if token.typ != itemIdent && token.typ != itemEndL && token.typ != itemEmptyLine {
  90. break
  91. }
  92. }
  93. t.backup()
  94. return token
  95. }
  96. // errorf formats the error and terminates processing.
  97. func (t *Tree) errorf(format string, args ...interface{}) {
  98. t.Root = nil
  99. format = fmt.Sprintf("template:%d: %s", t.token[0].line, format)
  100. panic(fmt.Errorf(format, args...))
  101. }
  102. //
  103. //
  104. //
  105. // recover is the handler that turns panics into returns from the top level of Parse.
  106. func (t *Tree) recover(errp *error) {
  107. e := recover()
  108. if e != nil {
  109. if _, ok := e.(runtime.Error); ok {
  110. panic(e)
  111. }
  112. if t != nil {
  113. t.lex.drain()
  114. t.lex = nil
  115. }
  116. *errp = e.(error)
  117. }
  118. }
  119. func (t *Tree) Parse(text []byte) (tree *Tree, err error) {
  120. defer t.recover(&err)
  121. t.lex = lex(t.Name, text)
  122. t.text = string(text)
  123. t.topParse()
  124. t.lex = nil
  125. return t, nil
  126. }
  127. // New allocates a new parse tree with the given name.
  128. func New(name string) *Tree {
  129. return NewWithReadFunc(name, ioutil.ReadFile)
  130. }
  131. // NewWithReadFunc same as `New` but it overrides the template's contents reader.
  132. func NewWithReadFunc(name string, readFunc func(string) ([]byte, error)) *Tree {
  133. return &Tree{
  134. Name: name,
  135. ReadFunc: readFunc,
  136. mixin: map[string]*MixinNode{},
  137. block: map[string]*ListNode{},
  138. }
  139. }