...

Source file src/github.com/godbus/dbus/v5/variant_lexer.go

Documentation: github.com/godbus/dbus/v5

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

View as plain text