diff --git a/promql/generated_parser.y b/promql/generated_parser.y index 73c4531b62..dc7d3698d4 100644 --- a/promql/generated_parser.y +++ b/promql/generated_parser.y @@ -199,7 +199,7 @@ aggregate_expr : aggregate_op aggregate_modifier function_call_body | aggregate_op function_call_body { $$ = yylex.(*parser).newAggregateExpr($1, &AggregateExpr{}, $2) } | aggregate_op error - { yylex.(*parser).unexpected("aggregation","") } + { yylex.(*parser).unexpected("aggregation",""); $$ = nil } ; aggregate_modifier: @@ -294,7 +294,7 @@ grouping_labels : LEFT_PAREN grouping_label_list RIGHT_PAREN | LEFT_PAREN RIGHT_PAREN { $$ = []string{} } | error - { yylex.(*parser).unexpected("grouping opts", "\"(\"") } + { yylex.(*parser).unexpected("grouping opts", "\"(\""); $$ = nil } ; @@ -304,7 +304,7 @@ grouping_label_list: | grouping_label { $$ = []string{$1.Val} } | grouping_label_list error - { yylex.(*parser).unexpected("grouping opts", "\",\" or \")\"") } + { yylex.(*parser).unexpected("grouping opts", "\",\" or \")\""); $$ = $1 } ; grouping_label : maybe_label @@ -315,7 +315,7 @@ grouping_label : maybe_label $$ = $1 } | 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)) } | 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 } | 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 - { yylex.(*parser).unexpected("subquery selector", "\"]\"") } + { yylex.(*parser).unexpected("subquery selector", "\"]\""); $$ = $1 } | 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 - { yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"") } + { yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\""); $$ = $1 } | 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 - { $$ = append($1, $3)} + { + if $1 != nil{ + $$ = append($1, $3) + } else { + $$ = $1 + } + } | label_matcher { $$ = []*labels.Matcher{$1}} | label_match_list error - { yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") } + { yylex.(*parser).unexpected("label matching", "\",\" or \"}\""); $$ = $1 } ; label_matcher : IDENTIFIER match_op STRING - { $$ = yylex.(*parser).newLabelMatcher($1, $2, $3) } + { $$ = yylex.(*parser).newLabelMatcher($1, $2, $3); } | IDENTIFIER match_op error - { yylex.(*parser).unexpected("label matching", "string")} + { yylex.(*parser).unexpected("label matching", "string"); $$ = nil} | IDENTIFIER error - { yylex.(*parser).unexpected("label matching", "label matching operator") } + { yylex.(*parser).unexpected("label matching", "label matching operator"); $$ = nil } | 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 { $$ = []labels.Label{$1} } | label_set_list error - { yylex.(*parser).unexpected("label set", "\",\" or \"}\"", ) } + { yylex.(*parser).unexpected("label set", "\",\" or \"}\"", ); $$ = $1 } ; label_set_item : IDENTIFIER EQL STRING { $$ = labels.Label{Name: $1.Val, Value: yylex.(*parser).unquoteString($3.Val) } } | IDENTIFIER EQL error - { yylex.(*parser).unexpected("label set", "string")} + { yylex.(*parser).unexpected("label set", "string"); $$ = labels.Label{}} | IDENTIFIER error - { yylex.(*parser).unexpected("label set", "\"=\"")} + { yylex.(*parser).unexpected("label set", "\"=\""); $$ = labels.Label{}} | 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 { $$ = $1 } | error - { yylex.(*parser).unexpected("series values", "") } + { yylex.(*parser).unexpected("series values", ""); $$ = nil } ; series_item : BLANK diff --git a/promql/generated_parser.y.go b/promql/generated_parser.y.go index 99d568b659..2f7608da7e 100644 --- a/promql/generated_parser.y.go +++ b/promql/generated_parser.y.go @@ -183,7 +183,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyInitialStackSize = 16 -//line promql/generated_parser.y:695 +//line promql/generated_parser.y:706 //line yacctab:1 var yyExca = [...]int{ @@ -191,55 +191,55 @@ var yyExca = [...]int{ 1, -1, -2, 0, -1, 15, - 1, 102, - 10, 102, - 22, 102, + 1, 103, + 10, 103, + 22, 103, -2, 0, -1, 157, - 12, 163, - 13, 163, - 16, 163, - 17, 163, - 23, 163, - 26, 163, - 42, 163, - 45, 163, - 46, 163, - 47, 163, - 48, 163, - 49, 163, - 50, 163, - 51, 163, - 52, 163, - 53, 163, - 54, 163, - 55, 163, + 12, 164, + 13, 164, + 16, 164, + 17, 164, + 23, 164, + 26, 164, + 42, 164, + 45, 164, + 46, 164, + 47, 164, + 48, 164, + 49, 164, + 50, 164, + 51, 164, + 52, 164, + 53, 164, + 54, 164, + 55, 164, -2, 0, -1, 158, - 12, 163, - 13, 163, - 16, 163, - 17, 163, - 23, 163, - 26, 163, - 42, 163, - 45, 163, - 46, 163, - 47, 163, - 48, 163, - 49, 163, - 50, 163, - 51, 163, - 52, 163, - 53, 163, - 54, 163, - 55, 163, + 12, 164, + 13, 164, + 16, 164, + 17, 164, + 23, 164, + 26, 164, + 42, 164, + 45, 164, + 46, 164, + 47, 164, + 48, 164, + 49, 164, + 50, 164, + 51, 164, + 52, 164, + 53, 164, + 54, 164, + 55, 164, -2, 0, -1, 174, - 19, 161, + 19, 162, -2, 0, -1, 221, - 19, 162, + 19, 163, -2, 0, } @@ -342,17 +342,17 @@ var yyR1 = [...]int{ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 26, 26, 36, 36, 31, 31, 31, 31, 14, 14, 14, 14, 13, 13, 13, 4, 4, 28, 30, - 30, 29, 29, 37, 35, 35, 33, 39, 39, 39, - 39, 39, 40, 41, 41, 41, 32, 32, 32, 1, - 1, 1, 2, 2, 2, 2, 11, 11, 7, 7, - 9, 9, 9, 9, 10, 10, 10, 12, 12, 12, - 12, 45, 17, 17, 17, 17, 16, 16, 16, 16, - 16, 20, 20, 20, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, + 30, 29, 29, 29, 37, 35, 35, 33, 39, 39, + 39, 39, 39, 40, 41, 41, 41, 32, 32, 32, + 1, 1, 1, 2, 2, 2, 2, 11, 11, 7, + 7, 9, 9, 9, 9, 10, 10, 10, 12, 12, + 12, 12, 45, 17, 17, 17, 17, 16, 16, 16, + 16, 16, 20, 20, 20, 3, 3, 3, 3, 3, + 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, 8, 8, - 5, 5, 5, 5, 34, 19, 21, 21, 18, 42, - 38, 43, 43, 15, 15, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, + 8, 5, 5, 5, 5, 34, 19, 21, 21, 18, + 42, 38, 43, 43, 15, 15, } var yyR2 = [...]int{ @@ -362,17 +362,17 @@ var yyR2 = [...]int{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 0, 1, 3, 3, 1, 1, 3, 3, 3, 4, 2, 1, 3, 1, 2, 1, 1, 2, 3, - 2, 3, 1, 3, 3, 3, 4, 6, 6, 5, - 4, 3, 2, 2, 1, 1, 3, 4, 2, 3, - 1, 2, 3, 3, 2, 1, 2, 1, 1, 1, - 3, 4, 2, 0, 3, 1, 2, 3, 3, 2, - 1, 2, 0, 3, 2, 1, 1, 3, 1, 3, - 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 1, 2, 3, 3, 3, 4, 6, 6, + 5, 4, 3, 2, 2, 1, 1, 3, 4, 2, + 3, 1, 2, 3, 3, 2, 1, 2, 1, 1, + 1, 3, 4, 2, 0, 3, 1, 2, 3, 3, + 2, 1, 2, 0, 3, 2, 1, 1, 3, 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, 2, 2, 1, 1, - 1, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, + 1, 1, 0, 1, 0, 1, } var yyChk = [...]int{ @@ -403,30 +403,30 @@ var yyChk = [...]int{ } var yyDef = [...]int{ - 0, -2, 93, 93, 0, 0, 7, 6, 1, 93, - 87, 88, 89, 0, 2, -2, 3, 4, 8, 9, + 0, -2, 94, 94, 0, 0, 7, 6, 1, 94, + 88, 89, 90, 0, 2, -2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, - 89, 154, 0, 160, 0, 74, 75, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 148, 149, - 0, 5, 86, 0, 92, 95, 0, 100, 101, 105, + 90, 155, 0, 161, 0, 75, 76, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 149, 150, + 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, 0, 0, 0, 21, 22, - 0, 0, 0, 58, 0, 72, 73, 0, 78, 80, - 0, 85, 90, 0, 96, 0, 99, 104, 0, 40, + 0, 0, 0, 58, 0, 73, 74, 0, 79, 81, + 0, 86, 91, 0, 97, 0, 100, 105, 0, 40, 45, 46, 42, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 64, 65, 159, - 0, 71, 19, 20, 23, 0, 52, 24, 0, 60, - 62, 63, 76, 0, 81, 0, 84, 150, 151, 152, - 153, 91, 94, 97, 98, 103, 106, 108, 111, 112, - 113, 155, 0, 0, 25, 0, 0, -2, -2, 26, + 0, 0, 0, 0, 0, 0, 0, 65, 66, 160, + 0, 72, 19, 20, 23, 0, 52, 24, 0, 60, + 62, 64, 77, 0, 82, 0, 85, 151, 152, 153, + 154, 92, 95, 98, 99, 104, 107, 109, 112, 113, + 114, 156, 0, 0, 25, 0, 0, -2, -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 66, -2, 70, 0, 51, 54, 56, - 57, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 59, 0, 77, 79, 82, 83, - 0, 0, 0, 156, 157, 43, 44, 47, 164, 48, - 0, -2, 69, 49, 0, 55, 61, 107, 158, 109, - 0, 67, 68, 50, 53, 110, + 37, 38, 39, 67, -2, 71, 0, 51, 54, 56, + 57, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 59, 63, 78, 80, 83, 84, + 0, 0, 0, 157, 158, 43, 44, 47, 165, 48, + 0, -2, 70, 49, 0, 55, 61, 108, 159, 110, + 0, 68, 69, 50, 53, 111, } var yyTok1 = [...]int{ @@ -837,6 +837,7 @@ yydefault: //line promql/generated_parser.y:202 { yylex.(*parser).unexpected("aggregation", "") + yyVAL.node = nil } case 23: yyDollar = yyS[yypt-2 : yypt+1] @@ -1016,6 +1017,7 @@ yydefault: //line promql/generated_parser.y:297 { yylex.(*parser).unexpected("grouping opts", "\"(\"") + yyVAL.strings = nil } case 53: yyDollar = yyS[yypt-3 : yypt+1] @@ -1034,6 +1036,7 @@ yydefault: //line promql/generated_parser.y:307 { yylex.(*parser).unexpected("grouping opts", "\",\" or \")\"") + yyVAL.strings = yyDollar[1].strings } case 56: yyDollar = yyS[yypt-1 : yypt+1] @@ -1049,6 +1052,7 @@ yydefault: //line promql/generated_parser.y:318 { yylex.(*parser).unexpected("grouping opts", "label") + yyVAL.item = Item{} } case 58: yyDollar = yyS[yypt-2 : yypt+1] @@ -1092,27 +1096,35 @@ yydefault: yyVAL.node = Expressions{yyDollar[1].node.(Expr)} } case 63: - yyDollar = yyS[yypt-3 : yypt+1] -//line promql/generated_parser.y:359 + yyDollar = yyS[yypt-2 : yypt+1] +//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: 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 = yyDollar[1].node + yyVAL.node = &ParenExpr{Expr: yyDollar[2].node.(Expr), PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item)} } case 65: yyDollar = yyS[yypt-3 : yypt+1] //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: + 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] -//line promql/generated_parser.y:380 +//line promql/generated_parser.y:385 { var errMsg string vs, ok := yyDollar[1].node.(*VectorSelector) @@ -1133,9 +1145,9 @@ yydefault: EndPos: yylex.(*parser).lastClosing, } } - case 67: + case 68: yyDollar = yyS[yypt-6 : yypt+1] -//line promql/generated_parser.y:403 +//line promql/generated_parser.y:408 { yyVAL.node = &SubqueryExpr{ Expr: yyDollar[1].node.(Expr), @@ -1145,33 +1157,37 @@ yydefault: EndPos: yyDollar[6].item.Pos + 1, } } - case 68: + case 69: yyDollar = yyS[yypt-6 : yypt+1] -//line promql/generated_parser.y:413 +//line promql/generated_parser.y:418 { yylex.(*parser).unexpected("subquery selector", "\"]\"") - } - case 69: - yyDollar = yyS[yypt-5 : yypt+1] -//line promql/generated_parser.y:415 - { - yylex.(*parser).unexpected("subquery selector", "duration or \"]\"") + yyVAL.node = yyDollar[1].node } case 70: - yyDollar = yyS[yypt-4 : yypt+1] -//line promql/generated_parser.y:417 + yyDollar = yyS[yypt-5 : yypt+1] +//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: - yyDollar = yyS[yypt-3 : yypt+1] -//line promql/generated_parser.y:419 + yyDollar = yyS[yypt-4 : yypt+1] +//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: + 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] -//line promql/generated_parser.y:429 +//line promql/generated_parser.y:434 { if nl, ok := yyDollar[2].node.(*NumberLiteral); ok { 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} } } - case 73: + case 74: yyDollar = yyS[yypt-2 : yypt+1] -//line promql/generated_parser.y:447 +//line promql/generated_parser.y:452 { vs := yyDollar[2].node.(*VectorSelector) vs.PosRange = mergeRanges(&yyDollar[1].item, vs) @@ -1193,9 +1209,9 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 74: + case 75: yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:455 +//line promql/generated_parser.y:460 { vs := &VectorSelector{ Name: yyDollar[1].item.Val, @@ -1205,228 +1221,241 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 75: + case 76: yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:465 +//line promql/generated_parser.y:470 { vs := yyDollar[1].node.(*VectorSelector) yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 76: + case 77: yyDollar = yyS[yypt-3 : yypt+1] -//line promql/generated_parser.y:473 +//line promql/generated_parser.y:478 { yyVAL.node = &VectorSelector{ LabelMatchers: yyDollar[2].matchers, PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item), } } - case 77: + case 78: yyDollar = yyS[yypt-4 : yypt+1] -//line promql/generated_parser.y:480 +//line promql/generated_parser.y:485 { yyVAL.node = &VectorSelector{ LabelMatchers: yyDollar[2].matchers, PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[4].item), } } - case 78: + case 79: yyDollar = yyS[yypt-2 : yypt+1] -//line promql/generated_parser.y:487 +//line promql/generated_parser.y:492 { yyVAL.node = &VectorSelector{ LabelMatchers: []*labels.Matcher{}, 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: + 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] -//line promql/generated_parser.y:498 +//line promql/generated_parser.y:509 { yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher} } - case 81: + case 82: yyDollar = yyS[yypt-2 : yypt+1] -//line promql/generated_parser.y:500 +//line promql/generated_parser.y:511 { yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") - } - 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) + yyVAL.matchers = yyDollar[1].matchers } case 83: 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: - yyDollar = yyS[yypt-2 : yypt+1] -//line promql/generated_parser.y:508 + yyDollar = yyS[yypt-3 : yypt+1] +//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: - yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:510 + yyDollar = yyS[yypt-2 : yypt+1] +//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: + 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] -//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}) sort.Sort(yyVAL.labels) } - case 87: + case 88: yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:520 +//line promql/generated_parser.y:531 { 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: - yyDollar = yyS[yypt-4 : yypt+1] -//line promql/generated_parser.y:529 + yyDollar = yyS[yypt-3 : yypt+1] +//line promql/generated_parser.y:538 { yyVAL.labels = labels.New(yyDollar[2].labels...) } case 92: - yyDollar = yyS[yypt-2 : yypt+1] -//line promql/generated_parser.y:531 + yyDollar = yyS[yypt-4 : yypt+1] +//line promql/generated_parser.y:540 { - yyVAL.labels = labels.New() + yyVAL.labels = labels.New(yyDollar[2].labels...) } case 93: - yyDollar = yyS[yypt-0 : yypt+1] -//line promql/generated_parser.y:533 + yyDollar = yyS[yypt-2 : yypt+1] +//line promql/generated_parser.y:542 { yyVAL.labels = labels.New() } case 94: - yyDollar = yyS[yypt-3 : yypt+1] -//line promql/generated_parser.y:537 + yyDollar = yyS[yypt-0 : yypt+1] +//line promql/generated_parser.y:544 { - yyVAL.labels = append(yyDollar[1].labels, yyDollar[3].label) + yyVAL.labels = labels.New() } 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] //line promql/generated_parser.y:548 { - yylex.(*parser).unexpected("label set", "string") + yyVAL.labels = append(yyDollar[1].labels, yyDollar[3].label) } - case 99: - yyDollar = yyS[yypt-2 : yypt+1] + case 96: + yyDollar = yyS[yypt-1 : yypt+1] //line promql/generated_parser.y:550 { - yylex.(*parser).unexpected("label set", "\"=\"") + yyVAL.labels = []labels.Label{yyDollar[1].label} } - case 100: - yyDollar = yyS[yypt-1 : yypt+1] + case 97: + yyDollar = yyS[yypt-2 : yypt+1] //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: + 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] -//line promql/generated_parser.y:560 +//line promql/generated_parser.y:571 { yylex.(*parser).generatedParserResult = &seriesDescription{ labels: yyDollar[1].labels, values: yyDollar[2].series, } } - case 102: + case 103: yyDollar = yyS[yypt-0 : yypt+1] -//line promql/generated_parser.y:569 +//line promql/generated_parser.y:580 { yyVAL.series = []sequenceValue{} } - case 103: + case 104: 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...) } - case 104: + case 105: yyDollar = yyS[yypt-2 : yypt+1] -//line promql/generated_parser.y:573 +//line promql/generated_parser.y:584 { 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: 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}} } - case 107: + case 108: yyDollar = yyS[yypt-3 : yypt+1] -//line promql/generated_parser.y:581 +//line promql/generated_parser.y:592 { yyVAL.series = []sequenceValue{} for i := uint64(0); i < yyDollar[3].uint; i++ { yyVAL.series = append(yyVAL.series, sequenceValue{omitted: true}) } } - case 108: + case 109: 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}} } - case 109: + case 110: yyDollar = yyS[yypt-3 : yypt+1] -//line promql/generated_parser.y:590 +//line promql/generated_parser.y:601 { yyVAL.series = []sequenceValue{} for i := uint64(0); i <= yyDollar[3].uint; i++ { yyVAL.series = append(yyVAL.series, sequenceValue{value: yyDollar[1].float}) } } - case 110: + case 111: yyDollar = yyS[yypt-4 : yypt+1] -//line promql/generated_parser.y:597 +//line promql/generated_parser.y:608 { yyVAL.series = []sequenceValue{} for i := uint64(0); i <= yyDollar[4].uint; i++ { @@ -1434,45 +1463,45 @@ yydefault: yyDollar[1].float += yyDollar[2].float } } - case 111: + case 112: yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:607 +//line promql/generated_parser.y:618 { if yyDollar[1].item.Val != "stale" { yylex.(*parser).unexpected("series values", "number or \"stale\"") } yyVAL.float = math.Float64frombits(value.StaleNaN) } - case 154: + case 155: yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:638 +//line promql/generated_parser.y:649 { yyVAL.node = &NumberLiteral{ Val: yylex.(*parser).number(yyDollar[1].item.Val), PosRange: yyDollar[1].item.PositionRange(), } } - case 155: + case 156: 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) } - case 156: + case 157: yyDollar = yyS[yypt-2 : yypt+1] -//line promql/generated_parser.y:648 +//line promql/generated_parser.y:659 { yyVAL.float = yyDollar[2].float } - case 157: + case 158: yyDollar = yyS[yypt-2 : yypt+1] -//line promql/generated_parser.y:649 +//line promql/generated_parser.y:660 { yyVAL.float = -yyDollar[2].float } - case 158: + case 159: yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:653 +//line promql/generated_parser.y:664 { var err error 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) } } - case 159: + case 160: yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:663 +//line promql/generated_parser.y:674 { var err error yyVAL.duration, err = parseDuration(yyDollar[1].item.Val) @@ -1490,24 +1519,24 @@ yydefault: yylex.(*parser).fail(yyDollar[1].item.PositionRange(), err) } } - case 160: + case 161: yyDollar = yyS[yypt-1 : yypt+1] -//line promql/generated_parser.y:674 +//line promql/generated_parser.y:685 { yyVAL.node = &StringLiteral{ Val: yylex.(*parser).unquoteString(yyDollar[1].item.Val), PosRange: yyDollar[1].item.PositionRange(), } } - case 161: + case 162: yyDollar = yyS[yypt-0 : yypt+1] -//line promql/generated_parser.y:687 +//line promql/generated_parser.y:698 { yyVAL.duration = 0 } - case 163: + case 164: yyDollar = yyS[yypt-0 : yypt+1] -//line promql/generated_parser.y:691 +//line promql/generated_parser.y:702 { yyVAL.strings = nil } diff --git a/promql/parse.go b/promql/parse.go index 2a6cd29d74..03494662da 100644 --- a/promql/parse.go +++ b/promql/parse.go @@ -48,11 +48,10 @@ type parser struct { yyParser yyParserImpl generatedParserResult interface{} + parseErrors ParseErrors } // 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 { PositionRange PositionRange Err error @@ -86,14 +85,43 @@ func (e *ParseErr) Error() string { 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. func ParseExpr(input string) (expr Expr, err error) { p := newParser(input) defer parserPool.Put(p) defer p.recover(&err) - expr = p.parseGenerated(START_EXPRESSION).(Expr) - err = p.typecheck(expr) + parseResult := p.parseGenerated(START_EXPRESSION) + + 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 } @@ -104,7 +132,16 @@ func ParseMetric(input string) (m labels.Labels, err error) { defer parserPool.Put(p) 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 @@ -114,7 +151,16 @@ func ParseMetricSelector(input string) (m []*labels.Matcher, err error) { defer parserPool.Put(p) 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. @@ -122,6 +168,7 @@ func newParser(input string) *parser { p := parserPool.Get().(*parser) p.injecting = false + p.parseErrors = nil // Clear lexer struct before reusing. p.lex = Lexer{ @@ -151,27 +198,26 @@ type seriesDescription struct { // parseSeriesDesc parses the description of a time series. func parseSeriesDesc(input string) (labels labels.Labels, values []sequenceValue, err error) { - p := newParser(input) p.lex.seriesDesc = true defer parserPool.Put(p) 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 - values = result.values + labels = result.labels + values = result.values - return -} + } -// typecheck checks correct typing of the parsed statements or expression. -func (p *parser) typecheck(node Node) (err error) { - defer p.recover(&err) + if len(p.parseErrors) != 0 { + err = p.parseErrors + } - p.checkType(node) - return nil + return labels, values, err } // failf formats the error and terminates processing. @@ -181,12 +227,13 @@ func (p *parser) failf(positionRange PositionRange, format string, args ...inter // fail terminates processing. func (p *parser) fail(positionRange PositionRange, err error) { - perr := &ParseErr{ + perr := ParseErr{ PositionRange: positionRange, Err: err, Query: p.lex.input, } - panic(perr) + + p.parseErrors = append(p.parseErrors, perr) } // unexpected creates a parser error complaining about an unexpected lexer item. @@ -258,6 +305,7 @@ func (p *parser) Lex(lval *yySymType) int { case ERROR: p.failf(lval.item.PositionRange(), "%s", lval.item.Val) + p.InjectItem(0) case EOF: lval.item.Typ = EOF p.InjectItem(0) @@ -340,7 +388,7 @@ func (p *parser) assembleVectorSelector(vs *VectorSelector) { if vs.Name != "" { 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) } } @@ -356,7 +404,7 @@ func (p *parser) assembleVectorSelector(vs *VectorSelector) { // implicit selection of all metrics (e.g. by a typo). notEmpty := false for _, lm := range vs.LabelMatchers { - if !lm.Matches("") { + if lm != nil && !lm.Matches("") { notEmpty = true break } diff --git a/promql/parse_test.go b/promql/parse_test.go index ffeaff210b..9bd6e57df4 100644 --- a/promql/parse_test.go +++ b/promql/parse_test.go @@ -1963,6 +1963,10 @@ var testExpr = []struct { input: `topk(some_metric)`, fail: true, 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)`, fail: true,