github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/logentry/logql/parser.go (about) 1 package logql 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 "text/scanner" 9 10 "github.com/prometheus/prometheus/model/labels" 11 ) 12 13 func init() { 14 // Improve the error messages coming out of yacc. 15 exprErrorVerbose = true 16 for str, tok := range tokens { 17 exprToknames[tok-exprPrivate+1] = str 18 } 19 } 20 21 // ParseExpr parses a string and returns an Expr. 22 func ParseExpr(input string) (Expr, error) { 23 l := lexer{ 24 parser: exprNewParser().(*exprParserImpl), 25 } 26 l.Init(strings.NewReader(input)) 27 l.Scanner.Error = func(_ *scanner.Scanner, msg string) { 28 l.Error(msg) 29 } 30 31 e := l.parser.Parse(&l) 32 if e != 0 || len(l.errs) > 0 { 33 return nil, l.errs[0] 34 } 35 return l.expr, nil 36 } 37 38 // ParseMatchers parses a string and returns labels matchers, if the expression contains 39 // anything else it will return an error. 40 func ParseMatchers(input string) ([]*labels.Matcher, error) { 41 expr, err := ParseExpr(input) 42 if err != nil { 43 return nil, err 44 } 45 matcherExpr, ok := expr.(*matchersExpr) 46 if !ok { 47 return nil, errors.New("only label matchers is supported") 48 } 49 return matcherExpr.matchers, nil 50 } 51 52 var tokens = map[string]int{ 53 ",": COMMA, 54 ".": DOT, 55 "{": OPEN_BRACE, 56 "}": CLOSE_BRACE, 57 "=": EQ, 58 "!=": NEQ, 59 "=~": RE, 60 "!~": NRE, 61 "|=": PIPE_EXACT, 62 "|~": PIPE_MATCH, 63 } 64 65 type lexer struct { 66 scanner.Scanner 67 errs []ParseError 68 expr Expr 69 parser *exprParserImpl 70 } 71 72 func (l *lexer) Lex(lval *exprSymType) int { 73 r := l.Scan() 74 75 switch r { 76 case scanner.EOF: 77 return 0 78 79 case scanner.String: 80 var err error 81 lval.str, err = strconv.Unquote(l.TokenText()) 82 if err != nil { 83 l.Error(err.Error()) 84 return 0 85 } 86 return STRING 87 } 88 89 if tok, ok := tokens[l.TokenText()+string(l.Peek())]; ok { 90 l.Next() 91 return tok 92 } 93 94 if tok, ok := tokens[l.TokenText()]; ok { 95 return tok 96 } 97 98 lval.str = l.TokenText() 99 return IDENTIFIER 100 } 101 102 func (l *lexer) Error(msg string) { 103 l.errs = append(l.errs, ParseError{ 104 msg: msg, 105 line: l.Line, 106 col: l.Column, 107 }) 108 } 109 110 // ParseError is what is returned when we failed to parse. 111 type ParseError struct { 112 msg string 113 line, col int 114 } 115 116 func (p ParseError) Error() string { 117 return fmt.Sprintf("parse error at line %d, col %d: %s", p.line, p.col, p.msg) 118 }