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  }