buffer.go 1.6 KB

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