buffer.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package xml // import "github.com/tdewolff/minify/xml"
  2. import "github.com/tdewolff/parse/xml"
  3. // Token is a single token unit with an attribute value (if given) and hash of the data.
  4. type Token struct {
  5. xml.TokenType
  6. Data []byte
  7. Text []byte
  8. AttrVal []byte
  9. }
  10. // TokenBuffer is a buffer that allows for token look-ahead.
  11. type TokenBuffer struct {
  12. l *xml.Lexer
  13. buf []Token
  14. pos int
  15. }
  16. // NewTokenBuffer returns a new TokenBuffer.
  17. func NewTokenBuffer(l *xml.Lexer) *TokenBuffer {
  18. return &TokenBuffer{
  19. l: l,
  20. buf: make([]Token, 0, 8),
  21. }
  22. }
  23. func (z *TokenBuffer) read(t *Token) {
  24. t.TokenType, t.Data = z.l.Next()
  25. t.Text = z.l.Text()
  26. if t.TokenType == xml.AttributeToken {
  27. t.AttrVal = z.l.AttrVal()
  28. } else {
  29. t.AttrVal = nil
  30. }
  31. }
  32. // Peek returns the ith element and possibly does an allocation.
  33. // Peeking past an error will panic.
  34. func (z *TokenBuffer) Peek(pos int) *Token {
  35. pos += z.pos
  36. if pos >= len(z.buf) {
  37. if len(z.buf) > 0 && z.buf[len(z.buf)-1].TokenType == xml.ErrorToken {
  38. return &z.buf[len(z.buf)-1]
  39. }
  40. c := cap(z.buf)
  41. d := len(z.buf) - z.pos
  42. p := pos - z.pos + 1 // required peek length
  43. var buf []Token
  44. if 2*p > c {
  45. buf = make([]Token, 0, 2*c+p)
  46. } else {
  47. buf = z.buf
  48. }
  49. copy(buf[:d], z.buf[z.pos:])
  50. buf = buf[:p]
  51. pos -= z.pos
  52. for i := d; i < p; i++ {
  53. z.read(&buf[i])
  54. if buf[i].TokenType == xml.ErrorToken {
  55. buf = buf[:i+1]
  56. pos = i
  57. break
  58. }
  59. }
  60. z.pos, z.buf = 0, buf
  61. }
  62. return &z.buf[pos]
  63. }
  64. // Shift returns the first element and advances position.
  65. func (z *TokenBuffer) Shift() *Token {
  66. if z.pos >= len(z.buf) {
  67. t := &z.buf[:1][0]
  68. z.read(t)
  69. return t
  70. }
  71. t := &z.buf[z.pos]
  72. z.pos++
  73. return t
  74. }