github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/log/jsonexpr/lexer.go (about) 1 package jsonexpr 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "strconv" 8 "text/scanner" 9 ) 10 11 type Scanner struct { 12 buf *bufio.Reader 13 data []interface{} 14 err error 15 debug bool 16 } 17 18 func NewScanner(r io.Reader, debug bool) *Scanner { 19 return &Scanner{ 20 buf: bufio.NewReader(r), 21 debug: debug, 22 } 23 } 24 25 func (sc *Scanner) Error(s string) { 26 sc.err = fmt.Errorf(s) 27 fmt.Printf("syntax error: %s\n", s) 28 } 29 30 func (sc *Scanner) Reduced(rule, state int, lval *JSONExprSymType) bool { 31 if sc.debug { 32 fmt.Printf("rule: %v; state %v; lval: %v\n", rule, state, lval) 33 } 34 return false 35 } 36 37 func (sc *Scanner) Lex(lval *JSONExprSymType) int { 38 return sc.lex(lval) 39 } 40 41 func (sc *Scanner) lex(lval *JSONExprSymType) int { 42 for { 43 r := sc.read() 44 45 if r == 0 { 46 return 0 47 } 48 if isWhitespace(r) { 49 continue 50 } 51 52 if isDigit(r) { 53 sc.unread() 54 val, err := sc.scanInt() 55 if err != nil { 56 sc.err = fmt.Errorf(err.Error()) 57 return 0 58 } 59 60 lval.int = val 61 return INDEX 62 } 63 64 switch true { 65 case r == '[': 66 return LSB 67 case r == ']': 68 return RSB 69 case r == '.': 70 return DOT 71 case isStartIdentifier(r): 72 sc.unread() 73 lval.field = sc.scanField() 74 return FIELD 75 case r == '"': 76 sc.unread() 77 lval.str = sc.scanStr() 78 return STRING 79 default: 80 sc.err = fmt.Errorf("unexpected char %c", r) 81 return 0 82 } 83 } 84 } 85 86 func isStartIdentifier(r rune) bool { 87 return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || r == '_' 88 } 89 90 func isIdentifier(r rune) bool { 91 return isStartIdentifier(r) || (r >= '0' && r <= '9') 92 } 93 94 func (sc *Scanner) scanField() string { 95 var str []rune 96 97 for { 98 r := sc.read() 99 if !isIdentifier(r) || isEndOfInput(r) { 100 sc.unread() 101 break 102 } 103 104 str = append(str, r) 105 } 106 return string(str) 107 } 108 109 func (sc *Scanner) scanStr() string { 110 var str []rune 111 //begin with ", end with " 112 r := sc.read() 113 if r != '"' { 114 sc.err = fmt.Errorf("unexpected char %c", r) 115 return "" 116 } 117 118 for { 119 r := sc.read() 120 if isEndOfInput(r) { 121 break 122 } 123 124 if r == '"' || r == ']' { 125 break 126 } 127 str = append(str, r) 128 } 129 return string(str) 130 } 131 132 func (sc *Scanner) scanInt() (int, error) { 133 var number []rune 134 135 for { 136 r := sc.read() 137 if r == '.' && len(number) > 0 { 138 return 0, fmt.Errorf("cannot use float as array index") 139 } 140 141 if isWhitespace(r) || r == '.' || r == ']' { 142 sc.unread() 143 break 144 } 145 146 if !isDigit(r) { 147 return 0, fmt.Errorf("non-integer value: %c", r) 148 } 149 150 number = append(number, r) 151 } 152 153 return strconv.Atoi(string(number)) 154 } 155 156 // input is either terminated by EOF or null byte 157 func isEndOfInput(r rune) bool { 158 return r == scanner.EOF || r == rune(0) 159 } 160 161 func (sc *Scanner) read() rune { 162 ch, _, _ := sc.buf.ReadRune() 163 return ch 164 } 165 166 func (sc *Scanner) unread() { _ = sc.buf.UnreadRune() } 167 168 func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' } 169 170 func isDigit(r rune) bool { 171 return r >= '0' && r <= '9' 172 }