PromQL: Don't panic on syntax errors (#6643)

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>
This commit is contained in:
Tobias Guggenmos 2020-01-16 16:20:20 +01:00 committed by Brian Brazil
parent bc42cf6806
commit 2ca25d1c96
4 changed files with 358 additions and 266 deletions

View File

@ -199,7 +199,7 @@ aggregate_expr : aggregate_op aggregate_modifier function_call_body
| aggregate_op function_call_body | aggregate_op function_call_body
{ $$ = yylex.(*parser).newAggregateExpr($1, &AggregateExpr{}, $2) } { $$ = yylex.(*parser).newAggregateExpr($1, &AggregateExpr{}, $2) }
| aggregate_op error | aggregate_op error
{ yylex.(*parser).unexpected("aggregation","") } { yylex.(*parser).unexpected("aggregation",""); $$ = nil }
; ;
aggregate_modifier: aggregate_modifier:
@ -294,7 +294,7 @@ grouping_labels : LEFT_PAREN grouping_label_list RIGHT_PAREN
| LEFT_PAREN RIGHT_PAREN | LEFT_PAREN RIGHT_PAREN
{ $$ = []string{} } { $$ = []string{} }
| error | error
{ yylex.(*parser).unexpected("grouping opts", "\"(\"") } { yylex.(*parser).unexpected("grouping opts", "\"(\""); $$ = nil }
; ;
@ -304,7 +304,7 @@ grouping_label_list:
| grouping_label | grouping_label
{ $$ = []string{$1.Val} } { $$ = []string{$1.Val} }
| grouping_label_list error | grouping_label_list error
{ yylex.(*parser).unexpected("grouping opts", "\",\" or \")\"") } { yylex.(*parser).unexpected("grouping opts", "\",\" or \")\""); $$ = $1 }
; ;
grouping_label : maybe_label grouping_label : maybe_label
@ -315,7 +315,7 @@ grouping_label : maybe_label
$$ = $1 $$ = $1
} }
| error | error
{ yylex.(*parser).unexpected("grouping opts", "label") } { yylex.(*parser).unexpected("grouping opts", "label"); $$ = Item{} }
; ;
/* /*
@ -349,6 +349,11 @@ function_call_args: function_call_args COMMA expr
{ $$ = append($1.(Expressions), $3.(Expr)) } { $$ = append($1.(Expressions), $3.(Expr)) }
| expr | expr
{ $$ = Expressions{$1.(Expr)} } { $$ = Expressions{$1.(Expr)} }
| function_call_args COMMA
{
yylex.(*parser).failf($2.PositionRange(), "trailing commas not allowed in function call args")
$$ = $1
}
; ;
/* /*
@ -369,7 +374,7 @@ offset_expr: expr OFFSET duration
$$ = $1 $$ = $1
} }
| expr OFFSET error | expr OFFSET error
{ yylex.(*parser).unexpected("offset", "duration") } { yylex.(*parser).unexpected("offset", "duration"); $$ = $1 }
; ;
/* /*
@ -410,13 +415,13 @@ subquery_expr : expr LEFT_BRACKET duration COLON maybe_duration RIGHT_BRACKET
} }
} }
| expr LEFT_BRACKET duration COLON duration error | expr LEFT_BRACKET duration COLON duration error
{ yylex.(*parser).unexpected("subquery selector", "\"]\"") } { yylex.(*parser).unexpected("subquery selector", "\"]\""); $$ = $1 }
| expr LEFT_BRACKET duration COLON error | expr LEFT_BRACKET duration COLON error
{ yylex.(*parser).unexpected("subquery selector", "duration or \"]\"") } { yylex.(*parser).unexpected("subquery selector", "duration or \"]\""); $$ = $1 }
| expr LEFT_BRACKET duration error | expr LEFT_BRACKET duration error
{ yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"") } { yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\""); $$ = $1 }
| expr LEFT_BRACKET error | expr LEFT_BRACKET error
{ yylex.(*parser).unexpected("subquery selector", "duration") } { yylex.(*parser).unexpected("subquery selector", "duration"); $$ = $1 }
; ;
/* /*
@ -493,21 +498,27 @@ label_matchers : LEFT_BRACE label_match_list RIGHT_BRACE
; ;
label_match_list: label_match_list COMMA label_matcher label_match_list: label_match_list COMMA label_matcher
{ $$ = append($1, $3)} {
if $1 != nil{
$$ = append($1, $3)
} else {
$$ = $1
}
}
| label_matcher | label_matcher
{ $$ = []*labels.Matcher{$1}} { $$ = []*labels.Matcher{$1}}
| label_match_list error | label_match_list error
{ yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") } { yylex.(*parser).unexpected("label matching", "\",\" or \"}\""); $$ = $1 }
; ;
label_matcher : IDENTIFIER match_op STRING label_matcher : IDENTIFIER match_op STRING
{ $$ = yylex.(*parser).newLabelMatcher($1, $2, $3) } { $$ = yylex.(*parser).newLabelMatcher($1, $2, $3); }
| IDENTIFIER match_op error | IDENTIFIER match_op error
{ yylex.(*parser).unexpected("label matching", "string")} { yylex.(*parser).unexpected("label matching", "string"); $$ = nil}
| IDENTIFIER error | IDENTIFIER error
{ yylex.(*parser).unexpected("label matching", "label matching operator") } { yylex.(*parser).unexpected("label matching", "label matching operator"); $$ = nil }
| error | error
{ yylex.(*parser).unexpected("label matching", "identifier or \"}\"")} { yylex.(*parser).unexpected("label matching", "identifier or \"}\""); $$ = nil}
; ;
/* /*
@ -538,18 +549,18 @@ label_set_list : label_set_list COMMA label_set_item
| label_set_item | label_set_item
{ $$ = []labels.Label{$1} } { $$ = []labels.Label{$1} }
| label_set_list error | label_set_list error
{ yylex.(*parser).unexpected("label set", "\",\" or \"}\"", ) } { yylex.(*parser).unexpected("label set", "\",\" or \"}\"", ); $$ = $1 }
; ;
label_set_item : IDENTIFIER EQL STRING label_set_item : IDENTIFIER EQL STRING
{ $$ = labels.Label{Name: $1.Val, Value: yylex.(*parser).unquoteString($3.Val) } } { $$ = labels.Label{Name: $1.Val, Value: yylex.(*parser).unquoteString($3.Val) } }
| IDENTIFIER EQL error | IDENTIFIER EQL error
{ yylex.(*parser).unexpected("label set", "string")} { yylex.(*parser).unexpected("label set", "string"); $$ = labels.Label{}}
| IDENTIFIER error | IDENTIFIER error
{ yylex.(*parser).unexpected("label set", "\"=\"")} { yylex.(*parser).unexpected("label set", "\"=\""); $$ = labels.Label{}}
| error | error
{ yylex.(*parser).unexpected("label set", "identifier or \"}\"") } { yylex.(*parser).unexpected("label set", "identifier or \"}\""); $$ = labels.Label{} }
; ;
/* /*
@ -572,7 +583,7 @@ series_values : /*empty*/
| series_values SPACE | series_values SPACE
{ $$ = $1 } { $$ = $1 }
| error | error
{ yylex.(*parser).unexpected("series values", "") } { yylex.(*parser).unexpected("series values", ""); $$ = nil }
; ;
series_item : BLANK series_item : BLANK

View File

@ -183,7 +183,7 @@ const yyEofCode = 1
const yyErrCode = 2 const yyErrCode = 2
const yyInitialStackSize = 16 const yyInitialStackSize = 16
//line promql/generated_parser.y:695 //line promql/generated_parser.y:706
//line yacctab:1 //line yacctab:1
var yyExca = [...]int{ var yyExca = [...]int{
@ -191,55 +191,55 @@ var yyExca = [...]int{
1, -1, 1, -1,
-2, 0, -2, 0,
-1, 15, -1, 15,
1, 102, 1, 103,
10, 102, 10, 103,
22, 102, 22, 103,
-2, 0, -2, 0,
-1, 157, -1, 157,
12, 163, 12, 164,
13, 163, 13, 164,
16, 163, 16, 164,
17, 163, 17, 164,
23, 163, 23, 164,
26, 163, 26, 164,
42, 163, 42, 164,
45, 163, 45, 164,
46, 163, 46, 164,
47, 163, 47, 164,
48, 163, 48, 164,
49, 163, 49, 164,
50, 163, 50, 164,
51, 163, 51, 164,
52, 163, 52, 164,
53, 163, 53, 164,
54, 163, 54, 164,
55, 163, 55, 164,
-2, 0, -2, 0,
-1, 158, -1, 158,
12, 163, 12, 164,
13, 163, 13, 164,
16, 163, 16, 164,
17, 163, 17, 164,
23, 163, 23, 164,
26, 163, 26, 164,
42, 163, 42, 164,
45, 163, 45, 164,
46, 163, 46, 164,
47, 163, 47, 164,
48, 163, 48, 164,
49, 163, 49, 164,
50, 163, 50, 164,
51, 163, 51, 164,
52, 163, 52, 164,
53, 163, 53, 164,
54, 163, 54, 164,
55, 163, 55, 164,
-2, 0, -2, 0,
-1, 174, -1, 174,
19, 161, 19, 162,
-2, 0, -2, 0,
-1, 221, -1, 221,
19, 162, 19, 163,
-2, 0, -2, 0,
} }
@ -342,17 +342,17 @@ var yyR1 = [...]int{
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
24, 26, 26, 36, 36, 31, 31, 31, 31, 14, 24, 26, 26, 36, 36, 31, 31, 31, 31, 14,
14, 14, 14, 13, 13, 13, 4, 4, 28, 30, 14, 14, 14, 13, 13, 13, 4, 4, 28, 30,
30, 29, 29, 37, 35, 35, 33, 39, 39, 39, 30, 29, 29, 29, 37, 35, 35, 33, 39, 39,
39, 39, 40, 41, 41, 41, 32, 32, 32, 1, 39, 39, 39, 40, 41, 41, 41, 32, 32, 32,
1, 1, 2, 2, 2, 2, 11, 11, 7, 7, 1, 1, 1, 2, 2, 2, 2, 11, 11, 7,
9, 9, 9, 9, 10, 10, 10, 12, 12, 12, 7, 9, 9, 9, 9, 10, 10, 10, 12, 12,
12, 45, 17, 17, 17, 17, 16, 16, 16, 16, 12, 12, 45, 17, 17, 17, 17, 16, 16, 16,
16, 20, 20, 20, 3, 3, 3, 3, 3, 3, 16, 16, 20, 20, 20, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8,
5, 5, 5, 5, 34, 19, 21, 21, 18, 42, 8, 5, 5, 5, 5, 34, 19, 21, 21, 18,
38, 43, 43, 15, 15, 42, 38, 43, 43, 15, 15,
} }
var yyR2 = [...]int{ var yyR2 = [...]int{
@ -362,17 +362,17 @@ var yyR2 = [...]int{
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
1, 0, 1, 3, 3, 1, 1, 3, 3, 3, 1, 0, 1, 3, 3, 1, 1, 3, 3, 3,
4, 2, 1, 3, 1, 2, 1, 1, 2, 3, 4, 2, 1, 3, 1, 2, 1, 1, 2, 3,
2, 3, 1, 3, 3, 3, 4, 6, 6, 5, 2, 3, 1, 2, 3, 3, 3, 4, 6, 6,
4, 3, 2, 2, 1, 1, 3, 4, 2, 3, 5, 4, 3, 2, 2, 1, 1, 3, 4, 2,
1, 2, 3, 3, 2, 1, 2, 1, 1, 1, 3, 1, 2, 3, 3, 2, 1, 2, 1, 1,
3, 4, 2, 0, 3, 1, 2, 3, 3, 2, 1, 3, 4, 2, 0, 3, 1, 2, 3, 3,
1, 2, 0, 3, 2, 1, 1, 3, 1, 3, 2, 1, 2, 0, 3, 2, 1, 1, 3, 1,
4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1,
1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1,
} }
var yyChk = [...]int{ var yyChk = [...]int{
@ -403,30 +403,30 @@ var yyChk = [...]int{
} }
var yyDef = [...]int{ var yyDef = [...]int{
0, -2, 93, 93, 0, 0, 7, 6, 1, 93, 0, -2, 94, 94, 0, 0, 7, 6, 1, 94,
87, 88, 89, 0, 2, -2, 3, 4, 8, 9, 88, 89, 90, 0, 2, -2, 3, 4, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0,
89, 154, 0, 160, 0, 74, 75, 114, 115, 116, 90, 155, 0, 161, 0, 75, 76, 115, 116, 117,
117, 118, 119, 120, 121, 122, 123, 124, 148, 149, 118, 119, 120, 121, 122, 123, 124, 125, 149, 150,
0, 5, 86, 0, 92, 95, 0, 100, 101, 105, 0, 5, 87, 0, 93, 96, 0, 101, 102, 106,
41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
41, 41, 41, 41, 41, 0, 0, 0, 21, 22, 41, 41, 41, 41, 41, 0, 0, 0, 21, 22,
0, 0, 0, 58, 0, 72, 73, 0, 78, 80, 0, 0, 0, 58, 0, 73, 74, 0, 79, 81,
0, 85, 90, 0, 96, 0, 99, 104, 0, 40, 0, 86, 91, 0, 97, 0, 100, 105, 0, 40,
45, 46, 42, 0, 0, 0, 0, 0, 0, 0, 45, 46, 42, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 64, 65, 159, 0, 0, 0, 0, 0, 0, 0, 65, 66, 160,
0, 71, 19, 20, 23, 0, 52, 24, 0, 60, 0, 72, 19, 20, 23, 0, 52, 24, 0, 60,
62, 63, 76, 0, 81, 0, 84, 150, 151, 152, 62, 64, 77, 0, 82, 0, 85, 151, 152, 153,
153, 91, 94, 97, 98, 103, 106, 108, 111, 112, 154, 92, 95, 98, 99, 104, 107, 109, 112, 113,
113, 155, 0, 0, 25, 0, 0, -2, -2, 26, 114, 156, 0, 0, 25, 0, 0, -2, -2, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 66, -2, 70, 0, 51, 54, 56, 37, 38, 39, 67, -2, 71, 0, 51, 54, 56,
57, 125, 126, 127, 128, 129, 130, 131, 132, 133, 57, 126, 127, 128, 129, 130, 131, 132, 133, 134,
134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
144, 145, 146, 147, 59, 0, 77, 79, 82, 83, 145, 146, 147, 148, 59, 63, 78, 80, 83, 84,
0, 0, 0, 156, 157, 43, 44, 47, 164, 48, 0, 0, 0, 157, 158, 43, 44, 47, 165, 48,
0, -2, 69, 49, 0, 55, 61, 107, 158, 109, 0, -2, 70, 49, 0, 55, 61, 108, 159, 110,
0, 67, 68, 50, 53, 110, 0, 68, 69, 50, 53, 111,
} }
var yyTok1 = [...]int{ var yyTok1 = [...]int{
@ -837,6 +837,7 @@ yydefault:
//line promql/generated_parser.y:202 //line promql/generated_parser.y:202
{ {
yylex.(*parser).unexpected("aggregation", "") yylex.(*parser).unexpected("aggregation", "")
yyVAL.node = nil
} }
case 23: case 23:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
@ -1016,6 +1017,7 @@ yydefault:
//line promql/generated_parser.y:297 //line promql/generated_parser.y:297
{ {
yylex.(*parser).unexpected("grouping opts", "\"(\"") yylex.(*parser).unexpected("grouping opts", "\"(\"")
yyVAL.strings = nil
} }
case 53: case 53:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
@ -1034,6 +1036,7 @@ yydefault:
//line promql/generated_parser.y:307 //line promql/generated_parser.y:307
{ {
yylex.(*parser).unexpected("grouping opts", "\",\" or \")\"") yylex.(*parser).unexpected("grouping opts", "\",\" or \")\"")
yyVAL.strings = yyDollar[1].strings
} }
case 56: case 56:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
@ -1049,6 +1052,7 @@ yydefault:
//line promql/generated_parser.y:318 //line promql/generated_parser.y:318
{ {
yylex.(*parser).unexpected("grouping opts", "label") yylex.(*parser).unexpected("grouping opts", "label")
yyVAL.item = Item{}
} }
case 58: case 58:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
@ -1092,27 +1096,35 @@ yydefault:
yyVAL.node = Expressions{yyDollar[1].node.(Expr)} yyVAL.node = Expressions{yyDollar[1].node.(Expr)}
} }
case 63: case 63:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:359 //line promql/generated_parser.y:353
{ {
yyVAL.node = &ParenExpr{Expr: yyDollar[2].node.(Expr), PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item)} yylex.(*parser).failf(yyDollar[2].item.PositionRange(), "trailing commas not allowed in function call args")
yyVAL.node = yyDollar[1].node
} }
case 64: case 64:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:367 //line promql/generated_parser.y:364
{ {
yylex.(*parser).addOffset(yyDollar[1].node, yyDollar[3].duration) yyVAL.node = &ParenExpr{Expr: yyDollar[2].node.(Expr), PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item)}
yyVAL.node = yyDollar[1].node
} }
case 65: case 65:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:372 //line promql/generated_parser.y:372
{ {
yylex.(*parser).unexpected("offset", "duration") yylex.(*parser).addOffset(yyDollar[1].node, yyDollar[3].duration)
yyVAL.node = yyDollar[1].node
} }
case 66: case 66:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:377
{
yylex.(*parser).unexpected("offset", "duration")
yyVAL.node = yyDollar[1].node
}
case 67:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:380 //line promql/generated_parser.y:385
{ {
var errMsg string var errMsg string
vs, ok := yyDollar[1].node.(*VectorSelector) vs, ok := yyDollar[1].node.(*VectorSelector)
@ -1133,9 +1145,9 @@ yydefault:
EndPos: yylex.(*parser).lastClosing, EndPos: yylex.(*parser).lastClosing,
} }
} }
case 67: case 68:
yyDollar = yyS[yypt-6 : yypt+1] yyDollar = yyS[yypt-6 : yypt+1]
//line promql/generated_parser.y:403 //line promql/generated_parser.y:408
{ {
yyVAL.node = &SubqueryExpr{ yyVAL.node = &SubqueryExpr{
Expr: yyDollar[1].node.(Expr), Expr: yyDollar[1].node.(Expr),
@ -1145,33 +1157,37 @@ yydefault:
EndPos: yyDollar[6].item.Pos + 1, EndPos: yyDollar[6].item.Pos + 1,
} }
} }
case 68: case 69:
yyDollar = yyS[yypt-6 : yypt+1] yyDollar = yyS[yypt-6 : yypt+1]
//line promql/generated_parser.y:413 //line promql/generated_parser.y:418
{ {
yylex.(*parser).unexpected("subquery selector", "\"]\"") yylex.(*parser).unexpected("subquery selector", "\"]\"")
} yyVAL.node = yyDollar[1].node
case 69:
yyDollar = yyS[yypt-5 : yypt+1]
//line promql/generated_parser.y:415
{
yylex.(*parser).unexpected("subquery selector", "duration or \"]\"")
} }
case 70: case 70:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-5 : yypt+1]
//line promql/generated_parser.y:417 //line promql/generated_parser.y:420
{ {
yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"") yylex.(*parser).unexpected("subquery selector", "duration or \"]\"")
yyVAL.node = yyDollar[1].node
} }
case 71: case 71:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:419 //line promql/generated_parser.y:422
{ {
yylex.(*parser).unexpected("subquery selector", "duration") yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"")
yyVAL.node = yyDollar[1].node
} }
case 72: case 72:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:424
{
yylex.(*parser).unexpected("subquery selector", "duration")
yyVAL.node = yyDollar[1].node
}
case 73:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:429 //line promql/generated_parser.y:434
{ {
if nl, ok := yyDollar[2].node.(*NumberLiteral); ok { if nl, ok := yyDollar[2].node.(*NumberLiteral); ok {
if yyDollar[1].item.Typ == SUB { if yyDollar[1].item.Typ == SUB {
@ -1183,9 +1199,9 @@ yydefault:
yyVAL.node = &UnaryExpr{Op: yyDollar[1].item.Typ, Expr: yyDollar[2].node.(Expr), StartPos: yyDollar[1].item.Pos} yyVAL.node = &UnaryExpr{Op: yyDollar[1].item.Typ, Expr: yyDollar[2].node.(Expr), StartPos: yyDollar[1].item.Pos}
} }
} }
case 73: case 74:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:447 //line promql/generated_parser.y:452
{ {
vs := yyDollar[2].node.(*VectorSelector) vs := yyDollar[2].node.(*VectorSelector)
vs.PosRange = mergeRanges(&yyDollar[1].item, vs) vs.PosRange = mergeRanges(&yyDollar[1].item, vs)
@ -1193,9 +1209,9 @@ yydefault:
yylex.(*parser).assembleVectorSelector(vs) yylex.(*parser).assembleVectorSelector(vs)
yyVAL.node = vs yyVAL.node = vs
} }
case 74: case 75:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:455 //line promql/generated_parser.y:460
{ {
vs := &VectorSelector{ vs := &VectorSelector{
Name: yyDollar[1].item.Val, Name: yyDollar[1].item.Val,
@ -1205,228 +1221,241 @@ yydefault:
yylex.(*parser).assembleVectorSelector(vs) yylex.(*parser).assembleVectorSelector(vs)
yyVAL.node = vs yyVAL.node = vs
} }
case 75: case 76:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:465 //line promql/generated_parser.y:470
{ {
vs := yyDollar[1].node.(*VectorSelector) vs := yyDollar[1].node.(*VectorSelector)
yylex.(*parser).assembleVectorSelector(vs) yylex.(*parser).assembleVectorSelector(vs)
yyVAL.node = vs yyVAL.node = vs
} }
case 76: case 77:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:473 //line promql/generated_parser.y:478
{ {
yyVAL.node = &VectorSelector{ yyVAL.node = &VectorSelector{
LabelMatchers: yyDollar[2].matchers, LabelMatchers: yyDollar[2].matchers,
PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item), PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item),
} }
} }
case 77: case 78:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:480 //line promql/generated_parser.y:485
{ {
yyVAL.node = &VectorSelector{ yyVAL.node = &VectorSelector{
LabelMatchers: yyDollar[2].matchers, LabelMatchers: yyDollar[2].matchers,
PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[4].item), PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[4].item),
} }
} }
case 78: case 79:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:487 //line promql/generated_parser.y:492
{ {
yyVAL.node = &VectorSelector{ yyVAL.node = &VectorSelector{
LabelMatchers: []*labels.Matcher{}, LabelMatchers: []*labels.Matcher{},
PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[2].item), PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[2].item),
} }
} }
case 79:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:496
{
yyVAL.matchers = append(yyDollar[1].matchers, yyDollar[3].matcher)
}
case 80: case 80:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:501
{
if yyDollar[1].matchers != nil {
yyVAL.matchers = append(yyDollar[1].matchers, yyDollar[3].matcher)
} else {
yyVAL.matchers = yyDollar[1].matchers
}
}
case 81:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:498 //line promql/generated_parser.y:509
{ {
yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher} yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher}
} }
case 81: case 82:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:500 //line promql/generated_parser.y:511
{ {
yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") yylex.(*parser).unexpected("label matching", "\",\" or \"}\"")
} yyVAL.matchers = yyDollar[1].matchers
case 82:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:504
{
yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item)
} }
case 83: case 83:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:506 //line promql/generated_parser.y:515
{ {
yylex.(*parser).unexpected("label matching", "string") yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item)
} }
case 84: case 84:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:508 //line promql/generated_parser.y:517
{ {
yylex.(*parser).unexpected("label matching", "label matching operator") yylex.(*parser).unexpected("label matching", "string")
yyVAL.matcher = nil
} }
case 85: case 85:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:510 //line promql/generated_parser.y:519
{ {
yylex.(*parser).unexpected("label matching", "identifier or \"}\"") yylex.(*parser).unexpected("label matching", "label matching operator")
yyVAL.matcher = nil
} }
case 86: case 86:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:521
{
yylex.(*parser).unexpected("label matching", "identifier or \"}\"")
yyVAL.matcher = nil
}
case 87:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:518 //line promql/generated_parser.y:529
{ {
yyVAL.labels = append(yyDollar[2].labels, labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val}) yyVAL.labels = append(yyDollar[2].labels, labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val})
sort.Sort(yyVAL.labels) sort.Sort(yyVAL.labels)
} }
case 87: case 88:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:520 //line promql/generated_parser.y:531
{ {
yyVAL.labels = yyDollar[1].labels yyVAL.labels = yyDollar[1].labels
} }
case 90:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:527
{
yyVAL.labels = labels.New(yyDollar[2].labels...)
}
case 91: case 91:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:529 //line promql/generated_parser.y:538
{ {
yyVAL.labels = labels.New(yyDollar[2].labels...) yyVAL.labels = labels.New(yyDollar[2].labels...)
} }
case 92: case 92:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:531 //line promql/generated_parser.y:540
{ {
yyVAL.labels = labels.New() yyVAL.labels = labels.New(yyDollar[2].labels...)
} }
case 93: case 93:
yyDollar = yyS[yypt-0 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:533 //line promql/generated_parser.y:542
{ {
yyVAL.labels = labels.New() yyVAL.labels = labels.New()
} }
case 94: case 94:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:537 //line promql/generated_parser.y:544
{ {
yyVAL.labels = append(yyDollar[1].labels, yyDollar[3].label) yyVAL.labels = labels.New()
} }
case 95: case 95:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:539
{
yyVAL.labels = []labels.Label{yyDollar[1].label}
}
case 96:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:541
{
yylex.(*parser).unexpected("label set", "\",\" or \"}\"")
}
case 97:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:546
{
yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)}
}
case 98:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:548 //line promql/generated_parser.y:548
{ {
yylex.(*parser).unexpected("label set", "string") yyVAL.labels = append(yyDollar[1].labels, yyDollar[3].label)
} }
case 99: case 96:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:550 //line promql/generated_parser.y:550
{ {
yylex.(*parser).unexpected("label set", "\"=\"") yyVAL.labels = []labels.Label{yyDollar[1].label}
} }
case 100: case 97:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:552 //line promql/generated_parser.y:552
{ {
yylex.(*parser).unexpected("label set", "identifier or \"}\"") yylex.(*parser).unexpected("label set", "\",\" or \"}\"")
yyVAL.labels = yyDollar[1].labels
}
case 98:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:557
{
yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)}
}
case 99:
yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:559
{
yylex.(*parser).unexpected("label set", "string")
yyVAL.label = labels.Label{}
}
case 100:
yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:561
{
yylex.(*parser).unexpected("label set", "\"=\"")
yyVAL.label = labels.Label{}
} }
case 101: case 101:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:563
{
yylex.(*parser).unexpected("label set", "identifier or \"}\"")
yyVAL.label = labels.Label{}
}
case 102:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:560 //line promql/generated_parser.y:571
{ {
yylex.(*parser).generatedParserResult = &seriesDescription{ yylex.(*parser).generatedParserResult = &seriesDescription{
labels: yyDollar[1].labels, labels: yyDollar[1].labels,
values: yyDollar[2].series, values: yyDollar[2].series,
} }
} }
case 102: case 103:
yyDollar = yyS[yypt-0 : yypt+1] yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:569 //line promql/generated_parser.y:580
{ {
yyVAL.series = []sequenceValue{} yyVAL.series = []sequenceValue{}
} }
case 103: case 104:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:571 //line promql/generated_parser.y:582
{ {
yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...) yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...)
} }
case 104: case 105:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:573 //line promql/generated_parser.y:584
{ {
yyVAL.series = yyDollar[1].series yyVAL.series = yyDollar[1].series
} }
case 105:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:575
{
yylex.(*parser).unexpected("series values", "")
}
case 106: case 106:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:579 //line promql/generated_parser.y:586
{
yylex.(*parser).unexpected("series values", "")
yyVAL.series = nil
}
case 107:
yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:590
{ {
yyVAL.series = []sequenceValue{{omitted: true}} yyVAL.series = []sequenceValue{{omitted: true}}
} }
case 107: case 108:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:581 //line promql/generated_parser.y:592
{ {
yyVAL.series = []sequenceValue{} yyVAL.series = []sequenceValue{}
for i := uint64(0); i < yyDollar[3].uint; i++ { for i := uint64(0); i < yyDollar[3].uint; i++ {
yyVAL.series = append(yyVAL.series, sequenceValue{omitted: true}) yyVAL.series = append(yyVAL.series, sequenceValue{omitted: true})
} }
} }
case 108: case 109:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:588 //line promql/generated_parser.y:599
{ {
yyVAL.series = []sequenceValue{{value: yyDollar[1].float}} yyVAL.series = []sequenceValue{{value: yyDollar[1].float}}
} }
case 109: case 110:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:590 //line promql/generated_parser.y:601
{ {
yyVAL.series = []sequenceValue{} yyVAL.series = []sequenceValue{}
for i := uint64(0); i <= yyDollar[3].uint; i++ { for i := uint64(0); i <= yyDollar[3].uint; i++ {
yyVAL.series = append(yyVAL.series, sequenceValue{value: yyDollar[1].float}) yyVAL.series = append(yyVAL.series, sequenceValue{value: yyDollar[1].float})
} }
} }
case 110: case 111:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:597 //line promql/generated_parser.y:608
{ {
yyVAL.series = []sequenceValue{} yyVAL.series = []sequenceValue{}
for i := uint64(0); i <= yyDollar[4].uint; i++ { for i := uint64(0); i <= yyDollar[4].uint; i++ {
@ -1434,45 +1463,45 @@ yydefault:
yyDollar[1].float += yyDollar[2].float yyDollar[1].float += yyDollar[2].float
} }
} }
case 111: case 112:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:607 //line promql/generated_parser.y:618
{ {
if yyDollar[1].item.Val != "stale" { if yyDollar[1].item.Val != "stale" {
yylex.(*parser).unexpected("series values", "number or \"stale\"") yylex.(*parser).unexpected("series values", "number or \"stale\"")
} }
yyVAL.float = math.Float64frombits(value.StaleNaN) yyVAL.float = math.Float64frombits(value.StaleNaN)
} }
case 154: case 155:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:638 //line promql/generated_parser.y:649
{ {
yyVAL.node = &NumberLiteral{ yyVAL.node = &NumberLiteral{
Val: yylex.(*parser).number(yyDollar[1].item.Val), Val: yylex.(*parser).number(yyDollar[1].item.Val),
PosRange: yyDollar[1].item.PositionRange(), PosRange: yyDollar[1].item.PositionRange(),
} }
} }
case 155: case 156:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:646 //line promql/generated_parser.y:657
{ {
yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val) yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val)
} }
case 156: case 157:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:648 //line promql/generated_parser.y:659
{ {
yyVAL.float = yyDollar[2].float yyVAL.float = yyDollar[2].float
} }
case 157: case 158:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:649 //line promql/generated_parser.y:660
{ {
yyVAL.float = -yyDollar[2].float yyVAL.float = -yyDollar[2].float
} }
case 158: case 159:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:653 //line promql/generated_parser.y:664
{ {
var err error var err error
yyVAL.uint, err = strconv.ParseUint(yyDollar[1].item.Val, 10, 64) yyVAL.uint, err = strconv.ParseUint(yyDollar[1].item.Val, 10, 64)
@ -1480,9 +1509,9 @@ yydefault:
yylex.(*parser).failf(yyDollar[1].item.PositionRange(), "invalid repetition in series values: %s", err) yylex.(*parser).failf(yyDollar[1].item.PositionRange(), "invalid repetition in series values: %s", err)
} }
} }
case 159: case 160:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:663 //line promql/generated_parser.y:674
{ {
var err error var err error
yyVAL.duration, err = parseDuration(yyDollar[1].item.Val) yyVAL.duration, err = parseDuration(yyDollar[1].item.Val)
@ -1490,24 +1519,24 @@ yydefault:
yylex.(*parser).fail(yyDollar[1].item.PositionRange(), err) yylex.(*parser).fail(yyDollar[1].item.PositionRange(), err)
} }
} }
case 160: case 161:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:674 //line promql/generated_parser.y:685
{ {
yyVAL.node = &StringLiteral{ yyVAL.node = &StringLiteral{
Val: yylex.(*parser).unquoteString(yyDollar[1].item.Val), Val: yylex.(*parser).unquoteString(yyDollar[1].item.Val),
PosRange: yyDollar[1].item.PositionRange(), PosRange: yyDollar[1].item.PositionRange(),
} }
} }
case 161: case 162:
yyDollar = yyS[yypt-0 : yypt+1] yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:687 //line promql/generated_parser.y:698
{ {
yyVAL.duration = 0 yyVAL.duration = 0
} }
case 163: case 164:
yyDollar = yyS[yypt-0 : yypt+1] yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:691 //line promql/generated_parser.y:702
{ {
yyVAL.strings = nil yyVAL.strings = nil
} }

View File

@ -48,11 +48,10 @@ type parser struct {
yyParser yyParserImpl yyParser yyParserImpl
generatedParserResult interface{} generatedParserResult interface{}
parseErrors ParseErrors
} }
// ParseErr wraps a parsing error with line and position context. // ParseErr wraps a parsing error with line and position context.
// If the parsing input was a single line, line will be 0 and omitted
// from the error string.
type ParseErr struct { type ParseErr struct {
PositionRange PositionRange PositionRange PositionRange
Err error Err error
@ -86,14 +85,43 @@ func (e *ParseErr) Error() string {
return fmt.Sprintf("%s parse error: %s", positionStr, e.Err) return fmt.Sprintf("%s parse error: %s", positionStr, e.Err)
} }
type ParseErrors []ParseErr
// Since producing multiple error messages might look weird when combined with error wrapping,
// only the first error produced by the parser is included in the error string.
// If getting the full error list is desired, it is recommended to typecast the error returned
// by the parser to ParseErrors and work with the underlying slice.
func (errs ParseErrors) Error() string {
if len(errs) != 0 {
return errs[0].Error()
} else {
// Should never happen
// Panicking while printing an error seems like a bad idea, so the
// situation is explained in the error message instead.
return "error contains no error message"
}
}
// ParseExpr returns the expression parsed from the input. // ParseExpr returns the expression parsed from the input.
func ParseExpr(input string) (expr Expr, err error) { func ParseExpr(input string) (expr Expr, err error) {
p := newParser(input) p := newParser(input)
defer parserPool.Put(p) defer parserPool.Put(p)
defer p.recover(&err) defer p.recover(&err)
expr = p.parseGenerated(START_EXPRESSION).(Expr) parseResult := p.parseGenerated(START_EXPRESSION)
err = p.typecheck(expr)
if parseResult != nil {
expr = parseResult.(Expr)
}
// Only typecheck when there are no syntax errors.
if len(p.parseErrors) == 0 {
p.checkType(expr)
}
if len(p.parseErrors) != 0 {
err = p.parseErrors
}
return expr, err return expr, err
} }
@ -104,7 +132,16 @@ func ParseMetric(input string) (m labels.Labels, err error) {
defer parserPool.Put(p) defer parserPool.Put(p)
defer p.recover(&err) defer p.recover(&err)
return p.parseGenerated(START_METRIC).(labels.Labels), nil parseResult := p.parseGenerated(START_METRIC)
if parseResult != nil {
m = parseResult.(labels.Labels)
}
if len(p.parseErrors) != 0 {
err = p.parseErrors
}
return m, err
} }
// ParseMetricSelector parses the provided textual metric selector into a list of // ParseMetricSelector parses the provided textual metric selector into a list of
@ -114,7 +151,16 @@ func ParseMetricSelector(input string) (m []*labels.Matcher, err error) {
defer parserPool.Put(p) defer parserPool.Put(p)
defer p.recover(&err) defer p.recover(&err)
return p.parseGenerated(START_METRIC_SELECTOR).(*VectorSelector).LabelMatchers, nil parseResult := p.parseGenerated(START_METRIC_SELECTOR)
if parseResult != nil {
m = parseResult.(*VectorSelector).LabelMatchers
}
if len(p.parseErrors) != 0 {
err = p.parseErrors
}
return m, err
} }
// newParser returns a new parser. // newParser returns a new parser.
@ -122,6 +168,7 @@ func newParser(input string) *parser {
p := parserPool.Get().(*parser) p := parserPool.Get().(*parser)
p.injecting = false p.injecting = false
p.parseErrors = nil
// Clear lexer struct before reusing. // Clear lexer struct before reusing.
p.lex = Lexer{ p.lex = Lexer{
@ -151,27 +198,26 @@ type seriesDescription struct {
// parseSeriesDesc parses the description of a time series. // parseSeriesDesc parses the description of a time series.
func parseSeriesDesc(input string) (labels labels.Labels, values []sequenceValue, err error) { func parseSeriesDesc(input string) (labels labels.Labels, values []sequenceValue, err error) {
p := newParser(input) p := newParser(input)
p.lex.seriesDesc = true p.lex.seriesDesc = true
defer parserPool.Put(p) defer parserPool.Put(p)
defer p.recover(&err) defer p.recover(&err)
result := p.parseGenerated(START_SERIES_DESCRIPTION).(*seriesDescription) parseResult := p.parseGenerated(START_SERIES_DESCRIPTION)
if parseResult != nil {
result := parseResult.(*seriesDescription)
labels = result.labels labels = result.labels
values = result.values values = result.values
return }
}
// typecheck checks correct typing of the parsed statements or expression. if len(p.parseErrors) != 0 {
func (p *parser) typecheck(node Node) (err error) { err = p.parseErrors
defer p.recover(&err) }
p.checkType(node) return labels, values, err
return nil
} }
// failf formats the error and terminates processing. // failf formats the error and terminates processing.
@ -181,12 +227,13 @@ func (p *parser) failf(positionRange PositionRange, format string, args ...inter
// fail terminates processing. // fail terminates processing.
func (p *parser) fail(positionRange PositionRange, err error) { func (p *parser) fail(positionRange PositionRange, err error) {
perr := &ParseErr{ perr := ParseErr{
PositionRange: positionRange, PositionRange: positionRange,
Err: err, Err: err,
Query: p.lex.input, Query: p.lex.input,
} }
panic(perr)
p.parseErrors = append(p.parseErrors, perr)
} }
// unexpected creates a parser error complaining about an unexpected lexer item. // unexpected creates a parser error complaining about an unexpected lexer item.
@ -258,6 +305,7 @@ func (p *parser) Lex(lval *yySymType) int {
case ERROR: case ERROR:
p.failf(lval.item.PositionRange(), "%s", lval.item.Val) p.failf(lval.item.PositionRange(), "%s", lval.item.Val)
p.InjectItem(0)
case EOF: case EOF:
lval.item.Typ = EOF lval.item.Typ = EOF
p.InjectItem(0) p.InjectItem(0)
@ -340,7 +388,7 @@ func (p *parser) assembleVectorSelector(vs *VectorSelector) {
if vs.Name != "" { if vs.Name != "" {
for _, m := range vs.LabelMatchers { for _, m := range vs.LabelMatchers {
if m.Name == labels.MetricName { if m != nil && m.Name == labels.MetricName {
p.failf(vs.PositionRange(), "metric name must not be set twice: %q or %q", vs.Name, m.Value) p.failf(vs.PositionRange(), "metric name must not be set twice: %q or %q", vs.Name, m.Value)
} }
} }
@ -356,7 +404,7 @@ func (p *parser) assembleVectorSelector(vs *VectorSelector) {
// implicit selection of all metrics (e.g. by a typo). // implicit selection of all metrics (e.g. by a typo).
notEmpty := false notEmpty := false
for _, lm := range vs.LabelMatchers { for _, lm := range vs.LabelMatchers {
if !lm.Matches("") { if lm != nil && !lm.Matches("") {
notEmpty = true notEmpty = true
break break
} }

View File

@ -1963,6 +1963,10 @@ var testExpr = []struct {
input: `topk(some_metric)`, input: `topk(some_metric)`,
fail: true, fail: true,
errMsg: "wrong number of arguments for aggregate expression provided, expected 2, got 1", errMsg: "wrong number of arguments for aggregate expression provided, expected 2, got 1",
}, {
input: `topk(some_metric,)`,
fail: true,
errMsg: "trailing commas not allowed in function call args",
}, { }, {
input: `topk(some_metric, other_metric)`, input: `topk(some_metric, other_metric)`,
fail: true, fail: true,