Better error messages.

Signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
pull/559/head
Tom Wilkie 6 years ago committed by Tom Wilkie
parent 80bbd04778
commit d1b873165a
  1. 128
      pkg/logql/expr.go
  2. 34
      pkg/logql/expr.y
  3. 32
      pkg/logql/parser.go
  4. 22
      pkg/logql/parser_test.go

@ -15,6 +15,8 @@ import (
type exprSymType struct {
yys int
Expr Expr
Filter labels.MatchType
Selector []*labels.Matcher
Matchers []*labels.Matcher
Matcher *labels.Matcher
str string
@ -61,56 +63,59 @@ const exprEofCode = 1
const exprErrCode = 2
const exprInitialStackSize = 16
//line pkg/logql/expr.y:51
//line pkg/logql/expr.y:65
//line yacctab:1
var exprExca = [...]int{
-1, 1,
1, -1,
-2, 0,
-1, 2,
1, 1,
-2, 0,
}
const exprPrivate = 57344
const exprLast = 26
const exprLast = 30
var exprAct = [...]int{
8, 10, 16, 17, 7, 3, 6, 18, 19, 20,
21, 4, 5, 26, 25, 24, 23, 15, 14, 22,
13, 12, 11, 9, 2, 1,
6, 13, 20, 4, 29, 18, 28, 10, 14, 9,
21, 22, 23, 24, 7, 8, 17, 19, 27, 16,
26, 25, 15, 12, 11, 14, 3, 5, 2, 1,
}
var exprPact = [...]int{
-7, -1000, -5, 18, 16, 15, 13, 12, -1000, -11,
-1000, -1, -1000, -1000, -1000, -1000, -1000, 18, 11, 10,
9, 8, -1000, -1000, -1000, -1000, -1000,
-9, -1000, -2, -1000, 21, 17, -1000, -1000, -1000, -1000,
-1000, 3, -11, -1000, 2, -1000, -1000, -1000, -1000, 4,
-1000, 15, 13, 1, -1, -1000, -1000, -1000, -1000, -1000,
}
var exprPgo = [...]int{
0, 25, 24, 23, 1,
0, 29, 28, 27, 26, 24, 1,
}
var exprR1 = [...]int{
0, 1, 2, 2, 2, 2, 2, 2, 2, 3,
3, 4, 4, 4, 4,
0, 1, 2, 2, 2, 2, 3, 3, 3, 3,
4, 4, 4, 5, 5, 6, 6, 6, 6,
}
var exprR2 = [...]int{
0, 1, 3, 3, 3, 3, 3, 2, 2, 1,
3, 3, 3, 3, 3,
0, 1, 1, 3, 3, 2, 1, 1, 1, 1,
3, 3, 3, 1, 3, 3, 3, 3, 3,
}
var exprChk = [...]int{
-1000, -1, -2, 12, 16, 17, 11, 9, 5, -3,
-4, 4, 5, 5, 5, 5, 13, 14, 8, 9,
10, 11, -4, 5, 5, 5, 5,
-1000, -1, -2, -4, 12, -3, 2, 16, 17, 11,
9, -5, 2, -6, 4, 5, 2, 13, 2, 14,
13, 8, 9, 10, 11, -6, 5, 5, 5, 5,
}
var exprDef = [...]int{
0, -2, 1, 0, 7, 0, 0, 0, 8, 0,
9, 0, 3, 4, 5, 6, 2, 0, 0, 0,
0, 0, 10, 11, 12, 13, 14,
0, -2, -2, 2, 0, 0, 5, 6, 7, 8,
9, 0, 0, 13, 0, 3, 4, 10, 11, 0,
12, 0, 0, 0, 0, 14, 15, 16, 17, 18,
}
var exprTok1 = [...]int{
@ -464,85 +469,96 @@ exprdefault:
case 1:
exprDollar = exprS[exprpt-1 : exprpt+1]
//line pkg/logql/expr.y:28
//line pkg/logql/expr.y:32
{
exprlex.(*lexer).expr = exprDollar[1].Expr
}
case 2:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:31
exprDollar = exprS[exprpt-1 : exprpt+1]
//line pkg/logql/expr.y:35
{
exprVAL.Expr = &matchersExpr{matchers: exprDollar[2].Matchers}
exprVAL.Expr = &matchersExpr{matchers: exprDollar[1].Selector}
}
case 3:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:32
//line pkg/logql/expr.y:36
{
exprVAL.Expr = NewFilterExpr(exprDollar[1].Expr, labels.MatchRegexp, exprDollar[3].str)
exprVAL.Expr = NewFilterExpr(exprDollar[1].Expr, exprDollar[2].Filter, exprDollar[3].str)
}
case 4:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:33
case 6:
exprDollar = exprS[exprpt-1 : exprpt+1]
//line pkg/logql/expr.y:42
{
exprVAL.Expr = NewFilterExpr(exprDollar[1].Expr, labels.MatchEqual, exprDollar[3].str)
exprVAL.Filter = labels.MatchRegexp
}
case 5:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:34
case 7:
exprDollar = exprS[exprpt-1 : exprpt+1]
//line pkg/logql/expr.y:43
{
exprVAL.Expr = NewFilterExpr(exprDollar[1].Expr, labels.MatchNotRegexp, exprDollar[3].str)
exprVAL.Filter = labels.MatchEqual
}
case 6:
case 8:
exprDollar = exprS[exprpt-1 : exprpt+1]
//line pkg/logql/expr.y:44
{
exprVAL.Filter = labels.MatchNotRegexp
}
case 9:
exprDollar = exprS[exprpt-1 : exprpt+1]
//line pkg/logql/expr.y:45
{
exprVAL.Filter = labels.MatchNotEqual
}
case 10:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:35
//line pkg/logql/expr.y:49
{
exprVAL.Expr = NewFilterExpr(exprDollar[1].Expr, labels.MatchNotEqual, exprDollar[3].str)
exprVAL.Selector = exprDollar[2].Matchers
}
case 7:
exprDollar = exprS[exprpt-2 : exprpt+1]
//line pkg/logql/expr.y:36
case 11:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:50
{
exprlex.(*lexer).Error("unexpected end of query, expected string")
exprVAL.Selector = exprDollar[2].Matchers
}
case 8:
exprDollar = exprS[exprpt-2 : exprpt+1]
//line pkg/logql/expr.y:37
case 12:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:51
{
exprlex.(*lexer).Error("unexpected string, expected pipe")
}
case 9:
case 13:
exprDollar = exprS[exprpt-1 : exprpt+1]
//line pkg/logql/expr.y:41
//line pkg/logql/expr.y:55
{
exprVAL.Matchers = []*labels.Matcher{exprDollar[1].Matcher}
}
case 10:
case 14:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:42
//line pkg/logql/expr.y:56
{
exprVAL.Matchers = append(exprDollar[1].Matchers, exprDollar[3].Matcher)
}
case 11:
case 15:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:46
//line pkg/logql/expr.y:60
{
exprVAL.Matcher = mustNewMatcher(labels.MatchEqual, exprDollar[1].str, exprDollar[3].str)
}
case 12:
case 16:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:47
//line pkg/logql/expr.y:61
{
exprVAL.Matcher = mustNewMatcher(labels.MatchNotEqual, exprDollar[1].str, exprDollar[3].str)
}
case 13:
case 17:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:48
//line pkg/logql/expr.y:62
{
exprVAL.Matcher = mustNewMatcher(labels.MatchRegexp, exprDollar[1].str, exprDollar[3].str)
}
case 14:
case 18:
exprDollar = exprS[exprpt-3 : exprpt+1]
//line pkg/logql/expr.y:49
//line pkg/logql/expr.y:63
{
exprVAL.Matcher = mustNewMatcher(labels.MatchNotRegexp, exprDollar[1].str, exprDollar[3].str)
}

@ -8,6 +8,8 @@ import (
%union{
Expr Expr
Filter labels.MatchType
Selector []*labels.Matcher
Matchers []*labels.Matcher
Matcher *labels.Matcher
str string
@ -16,9 +18,11 @@ import (
%start root
%type <Expr> expr
%type <Matchers> matchers
%type <Matcher> matcher
%type <Expr> expr
%type <Filter> filter
%type <Selector> selector
%type <Matchers> matchers
%type <Matcher> matcher
%token <str> IDENTIFIER STRING
%token <val> MATCHERS LABELS EQ NEQ RE NRE OPEN_BRACE CLOSE_BRACE COMMA DOT PIPE_MATCH PIPE_EXACT
@ -28,13 +32,23 @@ import (
root: expr { exprlex.(*lexer).expr = $1 };
expr:
OPEN_BRACE matchers CLOSE_BRACE { $$ = &matchersExpr{ matchers: $2 } }
| expr PIPE_MATCH STRING { $$ = NewFilterExpr( $1, labels.MatchRegexp, $3 ) }
| expr PIPE_EXACT STRING { $$ = NewFilterExpr( $1, labels.MatchEqual, $3 ) }
| expr NRE STRING { $$ = NewFilterExpr( $1, labels.MatchNotRegexp, $3 ) }
| expr NEQ STRING { $$ = NewFilterExpr( $1, labels.MatchNotEqual, $3 ) }
| expr PIPE_MATCH { exprlex.(*lexer).Error("unexpected end of query, expected string") }
| expr STRING { exprlex.(*lexer).Error("unexpected string, expected pipe") }
selector { $$ = &matchersExpr{ matchers: $1 } }
| expr filter STRING { $$ = NewFilterExpr( $1, $2, $3 ) }
| expr filter error
| expr error
;
filter:
PIPE_MATCH { $$ = labels.MatchRegexp }
| PIPE_EXACT { $$ = labels.MatchEqual }
| NRE { $$ = labels.MatchNotRegexp }
| NEQ { $$ = labels.MatchNotEqual }
;
selector:
OPEN_BRACE matchers CLOSE_BRACE { $$ = $2 }
| OPEN_BRACE matchers error { $$ = $2 }
| OPEN_BRACE error CLOSE_BRACE { }
;
matchers:

@ -7,18 +7,28 @@ import (
"text/scanner"
)
func init() {
// Improve the error messages coming out of yacc.
exprErrorVerbose = true
for str, tok := range tokens {
exprToknames[tok-exprPrivate+1] = str
}
}
// ParseExpr parses a string and returns an Expr.
func ParseExpr(input string) (Expr, error) {
var l lexer
var l = lexer{
parser: exprNewParser().(*exprParserImpl),
}
l.Init(strings.NewReader(input))
//l.Scanner.Mode = scanner.SkipComments | scanner.ScanStrings | scanner.ScanInts
l.Scanner.Error = func(_ *scanner.Scanner, msg string) {
l.Error(msg)
}
e := exprParse(&l)
if e != 0 || l.err != nil {
return nil, l.err
e := l.parser.Parse(&l)
if e != 0 || len(l.errs) > 0 {
return nil, l.errs[0]
}
return l.expr, nil
}
@ -38,8 +48,9 @@ var tokens = map[string]int{
type lexer struct {
scanner.Scanner
err error
expr Expr
errs []ParseError
expr Expr
parser *exprParserImpl
}
func (l *lexer) Lex(lval *exprSymType) int {
@ -73,16 +84,11 @@ func (l *lexer) Lex(lval *exprSymType) int {
}
func (l *lexer) Error(msg string) {
// We want to return the first error (from the lexer), and ignore subsequent ones.
if l.err != nil {
return
}
l.err = ParseError{
l.errs = append(l.errs, ParseError{
msg: msg,
line: l.Line,
col: l.Column,
}
})
}
// ParseError is what is returned when we failed to parse.

@ -119,18 +119,36 @@ func TestParse(t *testing.T) {
col: 6,
},
},
{
in: `{foo="bar"`,
err: ParseError{
msg: "syntax error: unexpected $end, expecting } or ,",
line: 1,
col: 11,
},
},
{
in: `{foo="bar"} |~`,
err: ParseError{
msg: "unexpected end of query, expected string",
msg: "syntax error: unexpected $end, expecting STRING",
line: 1,
col: 15,
},
},
{
in: `{foo="bar"} "foo"`,
err: ParseError{
msg: "unexpected string, expected pipe",
msg: "syntax error: unexpected STRING, expecting != or !~ or |~ or |=",
line: 1,
col: 13,
},
},
{
in: `{foo="bar"} foo`,
err: ParseError{
msg: "syntax error: unexpected IDENTIFIER, expecting != or !~ or |~ or |=",
line: 1,
col: 13,
},

Loading…
Cancel
Save