ini_lexer.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package ini
  2. import (
  3. "bytes"
  4. "io"
  5. "io/ioutil"
  6. "github.com/aws/aws-sdk-go/aws/awserr"
  7. )
  8. const (
  9. // ErrCodeUnableToReadFile is used when a file is failed to be
  10. // opened or read from.
  11. ErrCodeUnableToReadFile = "FailedRead"
  12. )
  13. // TokenType represents the various different tokens types
  14. type TokenType int
  15. func (t TokenType) String() string {
  16. switch t {
  17. case TokenNone:
  18. return "none"
  19. case TokenLit:
  20. return "literal"
  21. case TokenSep:
  22. return "sep"
  23. case TokenOp:
  24. return "op"
  25. case TokenWS:
  26. return "ws"
  27. case TokenNL:
  28. return "newline"
  29. case TokenComment:
  30. return "comment"
  31. case TokenComma:
  32. return "comma"
  33. default:
  34. return ""
  35. }
  36. }
  37. // TokenType enums
  38. const (
  39. TokenNone = TokenType(iota)
  40. TokenLit
  41. TokenSep
  42. TokenComma
  43. TokenOp
  44. TokenWS
  45. TokenNL
  46. TokenComment
  47. )
  48. type iniLexer struct{}
  49. // Tokenize will return a list of tokens during lexical analysis of the
  50. // io.Reader.
  51. func (l *iniLexer) Tokenize(r io.Reader) ([]Token, error) {
  52. b, err := ioutil.ReadAll(r)
  53. if err != nil {
  54. return nil, awserr.New(ErrCodeUnableToReadFile, "unable to read file", err)
  55. }
  56. return l.tokenize(b)
  57. }
  58. func (l *iniLexer) tokenize(b []byte) ([]Token, error) {
  59. runes := bytes.Runes(b)
  60. var err error
  61. n := 0
  62. tokenAmount := countTokens(runes)
  63. tokens := make([]Token, tokenAmount)
  64. count := 0
  65. for len(runes) > 0 && count < tokenAmount {
  66. switch {
  67. case isWhitespace(runes[0]):
  68. tokens[count], n, err = newWSToken(runes)
  69. case isComma(runes[0]):
  70. tokens[count], n = newCommaToken(), 1
  71. case isComment(runes):
  72. tokens[count], n, err = newCommentToken(runes)
  73. case isNewline(runes):
  74. tokens[count], n, err = newNewlineToken(runes)
  75. case isSep(runes):
  76. tokens[count], n, err = newSepToken(runes)
  77. case isOp(runes):
  78. tokens[count], n, err = newOpToken(runes)
  79. default:
  80. tokens[count], n, err = newLitToken(runes)
  81. }
  82. if err != nil {
  83. return nil, err
  84. }
  85. count++
  86. runes = runes[n:]
  87. }
  88. return tokens[:count], nil
  89. }
  90. func countTokens(runes []rune) int {
  91. count, n := 0, 0
  92. var err error
  93. for len(runes) > 0 {
  94. switch {
  95. case isWhitespace(runes[0]):
  96. _, n, err = newWSToken(runes)
  97. case isComma(runes[0]):
  98. _, n = newCommaToken(), 1
  99. case isComment(runes):
  100. _, n, err = newCommentToken(runes)
  101. case isNewline(runes):
  102. _, n, err = newNewlineToken(runes)
  103. case isSep(runes):
  104. _, n, err = newSepToken(runes)
  105. case isOp(runes):
  106. _, n, err = newOpToken(runes)
  107. default:
  108. _, n, err = newLitToken(runes)
  109. }
  110. if err != nil {
  111. return 0
  112. }
  113. count++
  114. runes = runes[n:]
  115. }
  116. return count + 1
  117. }
  118. // Token indicates a metadata about a given value.
  119. type Token struct {
  120. t TokenType
  121. ValueType ValueType
  122. base int
  123. raw []rune
  124. }
  125. var emptyValue = Value{}
  126. func newToken(t TokenType, raw []rune, v ValueType) Token {
  127. return Token{
  128. t: t,
  129. raw: raw,
  130. ValueType: v,
  131. }
  132. }
  133. // Raw return the raw runes that were consumed
  134. func (tok Token) Raw() []rune {
  135. return tok.raw
  136. }
  137. // Type returns the token type
  138. func (tok Token) Type() TokenType {
  139. return tok.t
  140. }