variant_lexer.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. package dbus
  2. import (
  3. "fmt"
  4. "strings"
  5. "unicode"
  6. "unicode/utf8"
  7. )
  8. // Heavily inspired by the lexer from text/template.
  9. type varToken struct {
  10. typ varTokenType
  11. val string
  12. }
  13. type varTokenType byte
  14. const (
  15. tokEOF varTokenType = iota
  16. tokError
  17. tokNumber
  18. tokString
  19. tokBool
  20. tokArrayStart
  21. tokArrayEnd
  22. tokDictStart
  23. tokDictEnd
  24. tokVariantStart
  25. tokVariantEnd
  26. tokComma
  27. tokColon
  28. tokType
  29. tokByteString
  30. )
  31. type varLexer struct {
  32. input string
  33. start int
  34. pos int
  35. width int
  36. tokens []varToken
  37. }
  38. type lexState func(*varLexer) lexState
  39. func varLex(s string) []varToken {
  40. l := &varLexer{input: s}
  41. l.run()
  42. return l.tokens
  43. }
  44. func (l *varLexer) accept(valid string) bool {
  45. if strings.IndexRune(valid, l.next()) >= 0 {
  46. return true
  47. }
  48. l.backup()
  49. return false
  50. }
  51. func (l *varLexer) backup() {
  52. l.pos -= l.width
  53. }
  54. func (l *varLexer) emit(t varTokenType) {
  55. l.tokens = append(l.tokens, varToken{t, l.input[l.start:l.pos]})
  56. l.start = l.pos
  57. }
  58. func (l *varLexer) errorf(format string, v ...interface{}) lexState {
  59. l.tokens = append(l.tokens, varToken{
  60. tokError,
  61. fmt.Sprintf(format, v...),
  62. })
  63. return nil
  64. }
  65. func (l *varLexer) ignore() {
  66. l.start = l.pos
  67. }
  68. func (l *varLexer) next() rune {
  69. var r rune
  70. if l.pos >= len(l.input) {
  71. l.width = 0
  72. return -1
  73. }
  74. r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
  75. l.pos += l.width
  76. return r
  77. }
  78. func (l *varLexer) run() {
  79. for state := varLexNormal; state != nil; {
  80. state = state(l)
  81. }
  82. }
  83. func (l *varLexer) peek() rune {
  84. r := l.next()
  85. l.backup()
  86. return r
  87. }
  88. func varLexNormal(l *varLexer) lexState {
  89. for {
  90. r := l.next()
  91. switch {
  92. case r == -1:
  93. l.emit(tokEOF)
  94. return nil
  95. case r == '[':
  96. l.emit(tokArrayStart)
  97. case r == ']':
  98. l.emit(tokArrayEnd)
  99. case r == '{':
  100. l.emit(tokDictStart)
  101. case r == '}':
  102. l.emit(tokDictEnd)
  103. case r == '<':
  104. l.emit(tokVariantStart)
  105. case r == '>':
  106. l.emit(tokVariantEnd)
  107. case r == ':':
  108. l.emit(tokColon)
  109. case r == ',':
  110. l.emit(tokComma)
  111. case r == '\'' || r == '"':
  112. l.backup()
  113. return varLexString
  114. case r == '@':
  115. l.backup()
  116. return varLexType
  117. case unicode.IsSpace(r):
  118. l.ignore()
  119. case unicode.IsNumber(r) || r == '+' || r == '-':
  120. l.backup()
  121. return varLexNumber
  122. case r == 'b':
  123. pos := l.start
  124. if n := l.peek(); n == '"' || n == '\'' {
  125. return varLexByteString
  126. }
  127. // not a byte string; try to parse it as a type or bool below
  128. l.pos = pos + 1
  129. l.width = 1
  130. fallthrough
  131. default:
  132. // either a bool or a type. Try bools first.
  133. l.backup()
  134. if l.pos+4 <= len(l.input) {
  135. if l.input[l.pos:l.pos+4] == "true" {
  136. l.pos += 4
  137. l.emit(tokBool)
  138. continue
  139. }
  140. }
  141. if l.pos+5 <= len(l.input) {
  142. if l.input[l.pos:l.pos+5] == "false" {
  143. l.pos += 5
  144. l.emit(tokBool)
  145. continue
  146. }
  147. }
  148. // must be a type.
  149. return varLexType
  150. }
  151. }
  152. }
  153. var varTypeMap = map[string]string{
  154. "boolean": "b",
  155. "byte": "y",
  156. "int16": "n",
  157. "uint16": "q",
  158. "int32": "i",
  159. "uint32": "u",
  160. "int64": "x",
  161. "uint64": "t",
  162. "double": "f",
  163. "string": "s",
  164. "objectpath": "o",
  165. "signature": "g",
  166. }
  167. func varLexByteString(l *varLexer) lexState {
  168. q := l.next()
  169. Loop:
  170. for {
  171. switch l.next() {
  172. case '\\':
  173. if r := l.next(); r != -1 {
  174. break
  175. }
  176. fallthrough
  177. case -1:
  178. return l.errorf("unterminated bytestring")
  179. case q:
  180. break Loop
  181. }
  182. }
  183. l.emit(tokByteString)
  184. return varLexNormal
  185. }
  186. func varLexNumber(l *varLexer) lexState {
  187. l.accept("+-")
  188. digits := "0123456789"
  189. if l.accept("0") {
  190. if l.accept("x") {
  191. digits = "0123456789abcdefABCDEF"
  192. } else {
  193. digits = "01234567"
  194. }
  195. }
  196. for strings.IndexRune(digits, l.next()) >= 0 {
  197. }
  198. l.backup()
  199. if l.accept(".") {
  200. for strings.IndexRune(digits, l.next()) >= 0 {
  201. }
  202. l.backup()
  203. }
  204. if l.accept("eE") {
  205. l.accept("+-")
  206. for strings.IndexRune("0123456789", l.next()) >= 0 {
  207. }
  208. l.backup()
  209. }
  210. if r := l.peek(); unicode.IsLetter(r) {
  211. l.next()
  212. return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
  213. }
  214. l.emit(tokNumber)
  215. return varLexNormal
  216. }
  217. func varLexString(l *varLexer) lexState {
  218. q := l.next()
  219. Loop:
  220. for {
  221. switch l.next() {
  222. case '\\':
  223. if r := l.next(); r != -1 {
  224. break
  225. }
  226. fallthrough
  227. case -1:
  228. return l.errorf("unterminated string")
  229. case q:
  230. break Loop
  231. }
  232. }
  233. l.emit(tokString)
  234. return varLexNormal
  235. }
  236. func varLexType(l *varLexer) lexState {
  237. at := l.accept("@")
  238. for {
  239. r := l.next()
  240. if r == -1 {
  241. break
  242. }
  243. if unicode.IsSpace(r) {
  244. l.backup()
  245. break
  246. }
  247. }
  248. if at {
  249. if _, err := ParseSignature(l.input[l.start+1 : l.pos]); err != nil {
  250. return l.errorf("%s", err)
  251. }
  252. } else {
  253. if _, ok := varTypeMap[l.input[l.start:l.pos]]; ok {
  254. l.emit(tokType)
  255. return varLexNormal
  256. }
  257. return l.errorf("unrecognized type %q", l.input[l.start:l.pos])
  258. }
  259. l.emit(tokType)
  260. return varLexNormal
  261. }