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  }