basestate.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package parser
  2. import (
  3. "bufio"
  4. "fmt"
  5. "strings"
  6. )
  7. const (
  8. startState = iota
  9. attrNameState
  10. attrValueState
  11. attrColonState
  12. multilineState
  13. )
  14. type baseState struct {
  15. r *bufio.Reader
  16. lineNumber *int
  17. }
  18. func newBaseState(r *bufio.Reader, lineNumber *int) *baseState {
  19. return &baseState{
  20. r: r,
  21. lineNumber: lineNumber,
  22. }
  23. }
  24. func (s *baseState) parseProperties() (map[string]string, error) {
  25. var r = s.r
  26. var attributes = make(map[string]string)
  27. var builder strings.Builder
  28. var key string
  29. var st = startState
  30. for {
  31. ch, err := s.read()
  32. if err != nil {
  33. return nil, err
  34. }
  35. switch st {
  36. case startState:
  37. switch {
  38. case isNewline(ch):
  39. return nil, fmt.Errorf("%q should be on the same line with %q", leftParenthesis, infoDirective)
  40. case isSpace(ch):
  41. continue
  42. case ch == leftParenthesis:
  43. st = attrNameState
  44. default:
  45. return nil, fmt.Errorf("unexpected char %q after %q", ch, infoDirective)
  46. }
  47. case attrNameState:
  48. switch {
  49. case isNewline(ch):
  50. if builder.Len() > 0 {
  51. return nil, fmt.Errorf("unexpected newline after %q", builder.String())
  52. }
  53. case isLetterDigit(ch):
  54. builder.WriteRune(ch)
  55. case isSpace(ch):
  56. if builder.Len() > 0 {
  57. key = builder.String()
  58. builder.Reset()
  59. st = attrColonState
  60. }
  61. case ch == colon:
  62. if builder.Len() == 0 {
  63. return nil, fmt.Errorf("unexpected leading %q", ch)
  64. }
  65. key = builder.String()
  66. builder.Reset()
  67. st = attrValueState
  68. case ch == rightParenthesis:
  69. return attributes, nil
  70. }
  71. case attrColonState:
  72. switch {
  73. case isSpace(ch):
  74. continue
  75. case ch == colon:
  76. st = attrValueState
  77. default:
  78. return nil, fmt.Errorf("bad char %q after %q in %q", ch, key, infoDirective)
  79. }
  80. case attrValueState:
  81. switch {
  82. case ch == multilineBeginTag:
  83. if builder.Len() > 0 {
  84. return nil, fmt.Errorf("%q before %q", builder.String(), multilineBeginTag)
  85. } else {
  86. st = multilineState
  87. }
  88. case isSpace(ch):
  89. if builder.Len() > 0 {
  90. builder.WriteRune(ch)
  91. }
  92. case isNewline(ch):
  93. attributes[key] = builder.String()
  94. builder.Reset()
  95. st = attrNameState
  96. case ch == rightParenthesis:
  97. attributes[key] = builder.String()
  98. builder.Reset()
  99. return attributes, nil
  100. default:
  101. builder.WriteRune(ch)
  102. }
  103. case multilineState:
  104. switch {
  105. case ch == multilineEndTag:
  106. attributes[key] = builder.String()
  107. builder.Reset()
  108. st = attrNameState
  109. case isNewline(ch):
  110. var multipleNewlines bool
  111. loopAfterNewline:
  112. for {
  113. next, err := read(r)
  114. if err != nil {
  115. return nil, err
  116. }
  117. switch {
  118. case isSpace(next):
  119. continue
  120. case isNewline(next):
  121. multipleNewlines = true
  122. default:
  123. if err := unread(r); err != nil {
  124. return nil, err
  125. }
  126. break loopAfterNewline
  127. }
  128. }
  129. if multipleNewlines {
  130. fmt.Fprintln(&builder)
  131. } else {
  132. builder.WriteByte(' ')
  133. }
  134. case ch == rightParenthesis:
  135. if builder.Len() > 0 {
  136. attributes[key] = builder.String()
  137. builder.Reset()
  138. }
  139. return attributes, nil
  140. default:
  141. builder.WriteRune(ch)
  142. }
  143. }
  144. }
  145. }
  146. func (s *baseState) read() (rune, error) {
  147. value, err := read(s.r)
  148. if err != nil {
  149. return 0, err
  150. }
  151. if isNewline(value) {
  152. *s.lineNumber++
  153. }
  154. return value, nil
  155. }
  156. func (s *baseState) readLine() (string, error) {
  157. line, _, err := s.r.ReadLine()
  158. if err != nil {
  159. return "", err
  160. }
  161. *s.lineNumber++
  162. return string(line), nil
  163. }
  164. func (s *baseState) skipSpaces() error {
  165. return skipSpaces(s.r)
  166. }
  167. func (s *baseState) unread() error {
  168. return unread(s.r)
  169. }