parse.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. "runtime"
  8. )
  9. // Tree is the representation of a single parsed template.
  10. type Tree struct {
  11. Name string // name of the template represented by the tree.
  12. Root *ListNode // top-level root of the tree.
  13. text string // text parsed to create the template (or its parent)
  14. // Parsing only; cleared after parse.
  15. lex *lexer
  16. token [3]item // three-token lookahead for parser.
  17. peekCount int
  18. tab int // depth of focus
  19. mixin map[string]*MixinNode
  20. block map[string]*ListNode
  21. }
  22. // Copy returns a copy of the Tree. Any parsing state is discarded.
  23. func (t *Tree) Copy() *Tree {
  24. if t == nil {
  25. return nil
  26. }
  27. return &Tree{
  28. Name: t.Name,
  29. Root: t.Root.CopyList(),
  30. text: t.text,
  31. }
  32. }
  33. // next returns the next token.
  34. func (t *Tree) next() item {
  35. if t.peekCount > 0 {
  36. t.peekCount--
  37. } else {
  38. t.token[0] = t.lex.nextItem()
  39. }
  40. return t.token[t.peekCount]
  41. }
  42. // backup backs the input stream up one token.
  43. func (t *Tree) backup() {
  44. t.peekCount++
  45. }
  46. // backup2 backs the input stream up two tokens.
  47. // The zeroth token is already there.
  48. func (t *Tree) backup2(t1 item) {
  49. t.token[1] = t1
  50. t.peekCount = 2
  51. }
  52. // backup3 backs the input stream up three tokens
  53. // The zeroth token is already there.
  54. func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back.
  55. t.token[1] = t1
  56. t.token[2] = t2
  57. t.peekCount = 3
  58. }
  59. // peek returns but does not consume the next token.
  60. func (t *Tree) peek() item {
  61. if t.peekCount > 0 {
  62. return t.token[t.peekCount-1]
  63. }
  64. t.peekCount = 1
  65. t.token[0] = t.lex.nextItem()
  66. return t.token[0]
  67. }
  68. // nextNonSpace returns the next non-space token.
  69. func (t *Tree) nextNonSpace() (token item) {
  70. for {
  71. token = t.next()
  72. if token.typ != itemIdent && token.typ != itemEndL && token.typ != itemEmptyLine {
  73. break
  74. }
  75. }
  76. // fmt.Println("\t\tnextNonSpace", token.val)
  77. return token
  78. }
  79. // peekNonSpace returns but does not consume the next non-space token.
  80. func (t *Tree) peekNonSpace() (token item) {
  81. for {
  82. token = t.next()
  83. if token.typ != itemIdent && token.typ != itemEndL && token.typ != itemEmptyLine {
  84. break
  85. }
  86. }
  87. t.backup()
  88. return token
  89. }
  90. // errorf formats the error and terminates processing.
  91. func (t *Tree) errorf(format string, args ...interface{}) {
  92. t.Root = nil
  93. format = fmt.Sprintf("template:%d: %s", t.token[0].line, format)
  94. panic(fmt.Errorf(format, args...))
  95. }
  96. //
  97. //
  98. //
  99. // recover is the handler that turns panics into returns from the top level of Parse.
  100. func (t *Tree) recover(errp *error) {
  101. e := recover()
  102. if e != nil {
  103. if _, ok := e.(runtime.Error); ok {
  104. panic(e)
  105. }
  106. if t != nil {
  107. t.lex.drain()
  108. t.lex = nil
  109. }
  110. *errp = e.(error)
  111. }
  112. }
  113. func (t *Tree) Parse(text string) (tree *Tree, err error) {
  114. defer t.recover(&err)
  115. t.lex = lex(t.Name, text)
  116. t.text = text
  117. t.topParse()
  118. t.lex = nil
  119. return t, nil
  120. }
  121. // New allocates a new parse tree with the given name.
  122. func New(name string) *Tree {
  123. return &Tree{
  124. Name: name,
  125. mixin: map[string]*MixinNode{},
  126. block: map[string]*ListNode{},
  127. }
  128. }