From af3277f8326431808ecec2a2095404ad3422a929 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Wed, 3 Dec 2025 18:46:35 +0100 Subject: [PATCH] PromQL: Add `fill*()` binop modifiers to provide default values for missing series Signed-off-by: Julius Volz --- promql/engine.go | 54 +- promql/parser/ast.go | 13 + promql/parser/generated_parser.y | 73 +- promql/parser/generated_parser.y.go | 1284 +++++++++-------- promql/parser/lex.go | 31 + promql/parser/parse.go | 6 + promql/parser/printer.go | 13 + promql/parser/printer_test.go | 20 + web/api/v1/translate_ast.go | 4 + .../ExplainViews/BinaryExpr/VectorVector.tsx | 73 +- web/ui/mantine-ui/src/promql/ast.ts | 5 + web/ui/mantine-ui/src/promql/binOp.test.ts | 24 + web/ui/mantine-ui/src/promql/binOp.ts | 29 +- web/ui/mantine-ui/src/promql/format.tsx | 43 +- web/ui/mantine-ui/src/promql/serialize.ts | 18 +- .../src/promql/serializeAndFormat.test.ts | 13 + .../src/complete/promql.terms.ts | 4 + .../src/parser/vector.test.ts | 85 +- .../codemirror-promql/src/parser/vector.ts | 35 + .../codemirror-promql/src/types/vector.ts | 7 + web/ui/module/lezer-promql/src/promql.grammar | 24 +- web/ui/module/lezer-promql/src/tokens.js | 140 +- 22 files changed, 1296 insertions(+), 702 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 57a1f41bb8..b609dc4f0a 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2862,7 +2862,8 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching * if matching.Card == parser.CardManyToMany { panic("many-to-many only allowed for set operators") } - if len(lhs) == 0 || len(rhs) == 0 { + if (len(lhs) == 0 && len(rhs) == 0) || + ((len(lhs) == 0 || len(rhs) == 0) && matching.FillValues.RHS == nil && matching.FillValues.LHS == nil) { return nil, nil // Short-circuit: nothing is going to match. } @@ -2910,17 +2911,9 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching * } matchedSigs := enh.matchedSigs - // For all lhs samples find a respective rhs sample and perform - // the binary operation. var lastErr error - for i, ls := range lhs { - sigOrd := lhsh[i].sigOrdinal - - rs, found := rightSigs[sigOrd] // Look for a match in the rhs Vector. - if !found { - continue - } + doBinOp := func(ls, rs Sample, sigOrd int) { // Account for potentially swapped sidedness. fl, fr := ls.F, rs.F hl, hr := ls.H, rs.H @@ -2931,7 +2924,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching * floatValue, histogramValue, keep, info, err := vectorElemBinop(op, fl, fr, hl, hr, pos) if err != nil { lastErr = err - continue + return } if info != nil { lastErr = info @@ -2971,7 +2964,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching * } if !keep && !returnBool { - continue + return } enh.Out = append(enh.Out, Sample{ @@ -2981,6 +2974,43 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching * DropName: returnBool, }) } + + // For all lhs samples, find a respective rhs sample and perform + // the binary operation. + for i, ls := range lhs { + sigOrd := lhsh[i].sigOrdinal + + rs, found := rightSigs[sigOrd] // Look for a match in the rhs Vector. + if !found { + fill := matching.FillValues.RHS + if fill == nil { + continue + } + rs = Sample{ + Metric: ls.Metric.MatchLabels(matching.On, matching.MatchingLabels...), + F: *fill, + } + } + + doBinOp(ls, rs, sigOrd) + } + + // For any rhs samples which have not been matched, check if we need to + // perform the operation with a fill value from the lhs. + if fill := matching.FillValues.LHS; fill != nil { + for sigOrd, rs := range rightSigs { + if _, matched := matchedSigs[sigOrd]; matched { + continue // Already matched. + } + ls := Sample{ + Metric: rs.Metric.MatchLabels(matching.On, matching.MatchingLabels...), + F: *fill, + } + + doBinOp(ls, rs, sigOrd) + } + } + return enh.Out, lastErr } diff --git a/promql/parser/ast.go b/promql/parser/ast.go index 130f9aefb7..6496095287 100644 --- a/promql/parser/ast.go +++ b/promql/parser/ast.go @@ -318,6 +318,19 @@ type VectorMatching struct { // Include contains additional labels that should be included in // the result from the side with the lower cardinality. Include []string + // Fill-in values to use when a series from one side does not find a match on the other side. + FillValues VectorMatchFillValues +} + +// VectorMatchFillValues contains the fill values to use for Vector matching +// when one side does not find a match on the other side. +// When a fill value is nil, no fill is applied for that side, and there +// is no output for the match group if there is no match. +type VectorMatchFillValues struct { + // RHS is the fill value to use for the right-hand side. + RHS *float64 + // LHS is the fill value to use for the left-hand side. + LHS *float64 } // Visitor allows visiting a Node and its child nodes. The Visit method is diff --git a/promql/parser/generated_parser.y b/promql/parser/generated_parser.y index 47776f53d0..71ab6ed4b3 100644 --- a/promql/parser/generated_parser.y +++ b/promql/parser/generated_parser.y @@ -139,6 +139,9 @@ BOOL BY GROUP_LEFT GROUP_RIGHT +FILL +FILL_LEFT +FILL_RIGHT IGNORING OFFSET SMOOTHED @@ -190,7 +193,7 @@ START_METRIC_SELECTOR %type int %type uint %type number series_value signed_number signed_or_unsigned_number -%type step_invariant_expr aggregate_expr aggregate_modifier bin_modifier binary_expr bool_modifier expr function_call function_call_args function_call_body group_modifiers label_matchers matrix_selector number_duration_literal offset_expr anchored_expr smoothed_expr on_or_ignoring paren_expr string_literal subquery_expr unary_expr vector_selector duration_expr paren_duration_expr positive_duration_expr offset_duration_expr +%type step_invariant_expr aggregate_expr aggregate_modifier bin_modifier fill_modifiers binary_expr bool_modifier expr function_call function_call_args function_call_body group_modifiers fill_value label_matchers matrix_selector number_duration_literal offset_expr anchored_expr smoothed_expr on_or_ignoring paren_expr string_literal subquery_expr unary_expr vector_selector duration_expr paren_duration_expr positive_duration_expr offset_duration_expr %start start @@ -302,7 +305,7 @@ binary_expr : expr ADD bin_modifier expr { $$ = yylex.(*parser).newBinar // Using left recursion for the modifier rules, helps to keep the parser stack small and // reduces allocations. -bin_modifier : group_modifiers; +bin_modifier : fill_modifiers; bool_modifier : /* empty */ { $$ = &BinaryExpr{ @@ -346,6 +349,47 @@ group_modifiers: bool_modifier /* empty */ } ; +fill_modifiers: group_modifiers /* empty */ + /* Only fill() */ + | group_modifiers FILL fill_value + { + $$ = $1 + fill := $3.(*NumberLiteral).Val + $$.(*BinaryExpr).VectorMatching.FillValues.LHS = &fill + $$.(*BinaryExpr).VectorMatching.FillValues.RHS = &fill + } + /* Only fill_left() */ + | group_modifiers FILL_LEFT fill_value + { + $$ = $1 + fill := $3.(*NumberLiteral).Val + $$.(*BinaryExpr).VectorMatching.FillValues.LHS = &fill + } + /* Only fill_right() */ + | group_modifiers FILL_RIGHT fill_value + { + $$ = $1 + fill := $3.(*NumberLiteral).Val + $$.(*BinaryExpr).VectorMatching.FillValues.RHS = &fill + } + /* fill_left() fill_right() */ + | group_modifiers FILL_LEFT fill_value FILL_RIGHT fill_value + { + $$ = $1 + fill_left := $3.(*NumberLiteral).Val + fill_right := $5.(*NumberLiteral).Val + $$.(*BinaryExpr).VectorMatching.FillValues.LHS = &fill_left + $$.(*BinaryExpr).VectorMatching.FillValues.RHS = &fill_right + } + /* fill_right() fill_left() */ + | group_modifiers FILL_RIGHT fill_value FILL_LEFT fill_value + { + fill_right := $3.(*NumberLiteral).Val + fill_left := $5.(*NumberLiteral).Val + $$.(*BinaryExpr).VectorMatching.FillValues.LHS = &fill_left + $$.(*BinaryExpr).VectorMatching.FillValues.RHS = &fill_right + } + ; grouping_labels : LEFT_PAREN grouping_label_list RIGHT_PAREN { $$ = $2 } @@ -387,6 +431,21 @@ grouping_label : maybe_label { yylex.(*parser).unexpected("grouping opts", "label"); $$ = Item{} } ; +fill_value : LEFT_PAREN number_duration_literal RIGHT_PAREN + { + $$ = $2.(*NumberLiteral) + } + | LEFT_PAREN unary_op number_duration_literal RIGHT_PAREN + { + nl := $3.(*NumberLiteral) + if $2.Typ == SUB { + nl.Val *= -1 + } + nl.PosRange.Start = $2.Pos + $$ = nl + } + ; + /* * Function calls. */ @@ -697,7 +756,7 @@ metric : metric_identifier label_set ; -metric_identifier: AVG | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | IDENTIFIER | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | QUANTILE | STDDEV | STDVAR | SUM | TOPK | WITHOUT | START | END | LIMITK | LIMIT_RATIO | STEP | RANGE | ANCHORED | SMOOTHED; +metric_identifier: AVG | BOTTOMK | BY | COUNT | COUNT_VALUES | FILL | FILL_LEFT | FILL_RIGHT | GROUP | IDENTIFIER | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | QUANTILE | STDDEV | STDVAR | SUM | TOPK | WITHOUT | START | END | LIMITK | LIMIT_RATIO | STEP | RANGE | ANCHORED | SMOOTHED; label_set : LEFT_BRACE label_set_list RIGHT_BRACE { $$ = labels.New($2...) } @@ -954,7 +1013,7 @@ counter_reset_hint : UNKNOWN_COUNTER_RESET | COUNTER_RESET | NOT_COUNTER_RESET | aggregate_op : AVG | BOTTOMK | COUNT | COUNT_VALUES | GROUP | MAX | MIN | QUANTILE | STDDEV | STDVAR | SUM | TOPK | LIMITK | LIMIT_RATIO; // Inside of grouping options label names can be recognized as keywords by the lexer. This is a list of keywords that could also be a label name. -maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK | START | END | ATAN2 | LIMITK | LIMIT_RATIO | STEP | RANGE | ANCHORED | SMOOTHED; +maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | FILL | FILL_LEFT | FILL_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK | START | END | ATAN2 | LIMITK | LIMIT_RATIO | STEP | RANGE | ANCHORED | SMOOTHED; unary_op : ADD | SUB; @@ -1162,7 +1221,7 @@ offset_duration_expr : number_duration_literal } | duration_expr ; - + min_max: MIN | MAX ; duration_expr : number_duration_literal @@ -1277,14 +1336,14 @@ duration_expr : number_duration_literal ; paren_duration_expr : LEFT_PAREN duration_expr RIGHT_PAREN - { + { yylex.(*parser).experimentalDurationExpr($2.(Expr)) if durationExpr, ok := $2.(*DurationExpr); ok { durationExpr.Wrapped = true $$ = durationExpr break } - $$ = $2 + $$ = $2 } ; diff --git a/promql/parser/generated_parser.y.go b/promql/parser/generated_parser.y.go index f5feec0b55..d20460ed5b 100644 --- a/promql/parser/generated_parser.y.go +++ b/promql/parser/generated_parser.y.go @@ -113,31 +113,34 @@ const BOOL = 57420 const BY = 57421 const GROUP_LEFT = 57422 const GROUP_RIGHT = 57423 -const IGNORING = 57424 -const OFFSET = 57425 -const SMOOTHED = 57426 -const ANCHORED = 57427 -const ON = 57428 -const WITHOUT = 57429 -const keywordsEnd = 57430 -const preprocessorStart = 57431 -const START = 57432 -const END = 57433 -const STEP = 57434 -const RANGE = 57435 -const preprocessorEnd = 57436 -const counterResetHintsStart = 57437 -const UNKNOWN_COUNTER_RESET = 57438 -const COUNTER_RESET = 57439 -const NOT_COUNTER_RESET = 57440 -const GAUGE_TYPE = 57441 -const counterResetHintsEnd = 57442 -const startSymbolsStart = 57443 -const START_METRIC = 57444 -const START_SERIES_DESCRIPTION = 57445 -const START_EXPRESSION = 57446 -const START_METRIC_SELECTOR = 57447 -const startSymbolsEnd = 57448 +const FILL = 57424 +const FILL_LEFT = 57425 +const FILL_RIGHT = 57426 +const IGNORING = 57427 +const OFFSET = 57428 +const SMOOTHED = 57429 +const ANCHORED = 57430 +const ON = 57431 +const WITHOUT = 57432 +const keywordsEnd = 57433 +const preprocessorStart = 57434 +const START = 57435 +const END = 57436 +const STEP = 57437 +const RANGE = 57438 +const preprocessorEnd = 57439 +const counterResetHintsStart = 57440 +const UNKNOWN_COUNTER_RESET = 57441 +const COUNTER_RESET = 57442 +const NOT_COUNTER_RESET = 57443 +const GAUGE_TYPE = 57444 +const counterResetHintsEnd = 57445 +const startSymbolsStart = 57446 +const START_METRIC = 57447 +const START_SERIES_DESCRIPTION = 57448 +const START_EXPRESSION = 57449 +const START_METRIC_SELECTOR = 57450 +const startSymbolsEnd = 57451 var yyToknames = [...]string{ "$end", @@ -221,6 +224,9 @@ var yyToknames = [...]string{ "BY", "GROUP_LEFT", "GROUP_RIGHT", + "FILL", + "FILL_LEFT", + "FILL_RIGHT", "IGNORING", "OFFSET", "SMOOTHED", @@ -258,376 +264,403 @@ var yyExca = [...]int16{ -1, 1, 1, -1, -2, 0, - -1, 41, - 1, 150, - 10, 150, - 24, 150, + -1, 44, + 1, 161, + 10, 161, + 24, 161, -2, 0, - -1, 72, - 2, 193, - 15, 193, - 79, 193, - 87, 193, - -2, 107, - -1, 73, - 2, 194, - 15, 194, - 79, 194, - 87, 194, - -2, 108, - -1, 74, - 2, 195, - 15, 195, - 79, 195, - 87, 195, - -2, 110, -1, 75, - 2, 196, - 15, 196, - 79, 196, - 87, 196, - -2, 111, - -1, 76, - 2, 197, - 15, 197, - 79, 197, - 87, 197, - -2, 112, - -1, 77, - 2, 198, - 15, 198, - 79, 198, - 87, 198, - -2, 117, - -1, 78, - 2, 199, - 15, 199, - 79, 199, - 87, 199, - -2, 119, - -1, 79, - 2, 200, - 15, 200, - 79, 200, - 87, 200, - -2, 121, - -1, 80, - 2, 201, - 15, 201, - 79, 201, - 87, 201, - -2, 122, - -1, 81, - 2, 202, - 15, 202, - 79, 202, - 87, 202, - -2, 123, - -1, 82, - 2, 203, - 15, 203, - 79, 203, - 87, 203, - -2, 124, - -1, 83, 2, 204, 15, 204, 79, 204, - 87, 204, - -2, 125, - -1, 84, + 90, 204, + -2, 115, + -1, 76, 2, 205, 15, 205, 79, 205, - 87, 205, - -2, 129, - -1, 85, + 90, 205, + -2, 116, + -1, 77, 2, 206, 15, 206, 79, 206, - 87, 206, + 90, 206, + -2, 118, + -1, 78, + 2, 207, + 15, 207, + 79, 207, + 90, 207, + -2, 119, + -1, 79, + 2, 208, + 15, 208, + 79, 208, + 90, 208, + -2, 123, + -1, 80, + 2, 209, + 15, 209, + 79, 209, + 90, 209, + -2, 128, + -1, 81, + 2, 210, + 15, 210, + 79, 210, + 90, 210, -2, 130, - -1, 137, - 41, 274, - 42, 274, - 52, 274, - 53, 274, - 57, 274, + -1, 82, + 2, 211, + 15, 211, + 79, 211, + 90, 211, + -2, 132, + -1, 83, + 2, 212, + 15, 212, + 79, 212, + 90, 212, + -2, 133, + -1, 84, + 2, 213, + 15, 213, + 79, 213, + 90, 213, + -2, 134, + -1, 85, + 2, 214, + 15, 214, + 79, 214, + 90, 214, + -2, 135, + -1, 86, + 2, 215, + 15, 215, + 79, 215, + 90, 215, + -2, 136, + -1, 87, + 2, 216, + 15, 216, + 79, 216, + 90, 216, + -2, 140, + -1, 88, + 2, 217, + 15, 217, + 79, 217, + 90, 217, + -2, 141, + -1, 140, + 41, 288, + 42, 288, + 52, 288, + 53, 288, + 57, 288, -2, 22, - -1, 251, - 9, 259, - 12, 259, - 13, 259, - 18, 259, - 19, 259, - 25, 259, - 41, 259, - 47, 259, - 48, 259, - 51, 259, - 57, 259, - 62, 259, - 63, 259, - 64, 259, - 65, 259, - 66, 259, - 67, 259, - 68, 259, - 69, 259, - 70, 259, - 71, 259, - 72, 259, - 73, 259, - 74, 259, - 75, 259, - 79, 259, - 83, 259, - 84, 259, - 85, 259, - 87, 259, - 90, 259, - 91, 259, - 92, 259, - 93, 259, + -1, 258, + 9, 273, + 12, 273, + 13, 273, + 18, 273, + 19, 273, + 25, 273, + 41, 273, + 47, 273, + 48, 273, + 51, 273, + 57, 273, + 62, 273, + 63, 273, + 64, 273, + 65, 273, + 66, 273, + 67, 273, + 68, 273, + 69, 273, + 70, 273, + 71, 273, + 72, 273, + 73, 273, + 74, 273, + 75, 273, + 79, 273, + 82, 273, + 83, 273, + 84, 273, + 86, 273, + 87, 273, + 88, 273, + 90, 273, + 93, 273, + 94, 273, + 95, 273, + 96, 273, -2, 0, - -1, 252, - 9, 259, - 12, 259, - 13, 259, - 18, 259, - 19, 259, - 25, 259, - 41, 259, - 47, 259, - 48, 259, - 51, 259, - 57, 259, - 62, 259, - 63, 259, - 64, 259, - 65, 259, - 66, 259, - 67, 259, - 68, 259, - 69, 259, - 70, 259, - 71, 259, - 72, 259, - 73, 259, - 74, 259, - 75, 259, - 79, 259, - 83, 259, - 84, 259, - 85, 259, - 87, 259, - 90, 259, - 91, 259, - 92, 259, - 93, 259, + -1, 259, + 9, 273, + 12, 273, + 13, 273, + 18, 273, + 19, 273, + 25, 273, + 41, 273, + 47, 273, + 48, 273, + 51, 273, + 57, 273, + 62, 273, + 63, 273, + 64, 273, + 65, 273, + 66, 273, + 67, 273, + 68, 273, + 69, 273, + 70, 273, + 71, 273, + 72, 273, + 73, 273, + 74, 273, + 75, 273, + 79, 273, + 82, 273, + 83, 273, + 84, 273, + 86, 273, + 87, 273, + 88, 273, + 90, 273, + 93, 273, + 94, 273, + 95, 273, + 96, 273, -2, 0, } const yyPrivate = 57344 -const yyLast = 1050 +const yyLast = 1224 var yyAct = [...]int16{ - 58, 186, 413, 411, 341, 418, 286, 243, 197, 95, - 189, 48, 355, 144, 70, 227, 93, 251, 252, 356, - 159, 190, 65, 120, 17, 88, 127, 130, 128, 129, - 22, 425, 426, 427, 428, 131, 249, 121, 124, 335, - 250, 67, 132, 126, 408, 407, 377, 332, 125, 123, - 331, 102, 126, 122, 336, 154, 324, 6, 397, 18, - 19, 111, 112, 20, 135, 114, 137, 119, 101, 375, - 337, 323, 375, 330, 11, 12, 14, 15, 16, 21, - 23, 25, 26, 27, 28, 29, 33, 34, 43, 133, - 329, 13, 116, 118, 117, 24, 38, 37, 146, 30, - 402, 124, 31, 32, 35, 36, 130, 412, 138, 396, - 194, 125, 123, 328, 131, 126, 365, 182, 239, 401, - 193, 199, 204, 205, 206, 207, 208, 209, 177, 363, - 362, 181, 200, 200, 200, 200, 200, 200, 200, 178, - 120, 238, 223, 201, 201, 201, 201, 201, 201, 201, - 212, 215, 134, 200, 136, 211, 210, 2, 3, 4, - 5, 222, 233, 221, 201, 245, 235, 384, 333, 371, - 228, 247, 229, 360, 370, 359, 246, 358, 188, 273, - 140, 368, 114, 195, 119, 194, 277, 139, 62, 369, - 268, 237, 229, 271, 185, 193, 441, 200, 61, 196, - 367, 201, 273, 383, 155, 278, 279, 280, 201, 116, - 118, 117, 231, 200, 236, 121, 124, 195, 382, 440, - 86, 218, 230, 232, 201, 381, 125, 123, 276, 275, - 126, 122, 231, 196, 274, 146, 87, 132, 439, 327, - 429, 438, 230, 232, 248, 141, 184, 183, 419, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 334, 357, 191, 192, 214, 353, - 354, 202, 203, 361, 121, 124, 88, 364, 283, 7, - 39, 213, 282, 199, 200, 125, 123, 395, 200, 126, - 122, 366, 10, 194, 200, 201, 394, 281, 393, 201, - 392, 391, 90, 193, 390, 201, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 389, 194, 388, 120, 195, 373, 387, 386, 385, - 153, 99, 193, 62, 442, 374, 376, 200, 378, 185, - 56, 196, 40, 61, 379, 380, 89, 152, 201, 151, - 1, 100, 102, 103, 195, 104, 105, 175, 71, 108, - 109, 398, 111, 112, 113, 86, 114, 115, 119, 101, - 196, 66, 200, 55, 9, 9, 54, 404, 8, 53, - 406, 87, 41, 201, 52, 158, 410, 51, 414, 415, - 416, 184, 183, 116, 118, 117, 421, 420, 423, 422, - 417, 430, 50, 49, 289, 47, 156, 216, 147, 46, - 431, 432, 200, 372, 299, 433, 202, 203, 145, 96, - 305, 435, 157, 201, 403, 437, 326, 288, 147, 94, - 436, 97, 45, 44, 57, 242, 434, 234, 145, 338, - 443, 200, 97, 98, 121, 124, 143, 240, 284, 301, - 302, 97, 201, 303, 91, 125, 123, 424, 187, 126, - 122, 316, 287, 59, 290, 292, 294, 295, 296, 304, - 306, 309, 310, 311, 312, 313, 317, 318, 142, 0, - 291, 293, 297, 298, 300, 307, 322, 321, 308, 289, - 96, 0, 314, 315, 319, 320, 226, 150, 405, 299, - 94, 225, 149, 0, 0, 305, 0, 0, 92, 285, - 0, 0, 288, 97, 224, 148, 62, 121, 124, 0, - 0, 0, 272, 0, 0, 0, 61, 0, 125, 123, - 0, 0, 126, 122, 301, 302, 0, 0, 303, 0, - 0, 0, 0, 0, 0, 0, 316, 0, 86, 290, - 292, 294, 295, 296, 304, 306, 309, 310, 311, 312, - 313, 317, 318, 0, 87, 291, 293, 297, 298, 300, - 307, 322, 321, 308, 184, 183, 0, 314, 315, 319, - 320, 62, 0, 120, 60, 88, 0, 63, 0, 0, - 22, 61, 0, 0, 217, 0, 0, 64, 0, 269, - 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 100, 102, 0, 86, 0, 0, 0, 0, 0, 18, - 19, 111, 112, 20, 0, 114, 115, 119, 101, 87, - 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 0, 0, - 400, 13, 116, 118, 117, 24, 38, 37, 399, 30, - 0, 0, 31, 32, 68, 69, 62, 42, 0, 60, - 88, 0, 63, 0, 0, 22, 61, 121, 124, 0, - 0, 0, 64, 0, 121, 124, 0, 0, 125, 123, - 0, 0, 126, 122, 0, 125, 123, 0, 86, 126, - 122, 0, 0, 0, 18, 19, 0, 0, 20, 0, - 0, 0, 0, 0, 87, 0, 0, 0, 0, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 0, 0, 0, 13, 0, 0, 220, - 24, 38, 37, 0, 30, 0, 325, 31, 32, 68, - 69, 62, 0, 0, 60, 88, 0, 63, 121, 124, - 22, 61, 0, 0, 0, 0, 0, 64, 0, 125, - 123, 0, 0, 126, 122, 0, 0, 0, 0, 0, - 121, 124, 0, 86, 0, 0, 0, 0, 0, 18, - 19, 125, 123, 20, 0, 126, 122, 0, 0, 87, - 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 17, 39, - 0, 13, 0, 0, 22, 24, 38, 37, 0, 30, - 340, 0, 31, 32, 68, 69, 0, 339, 0, 0, - 0, 343, 344, 342, 349, 351, 348, 350, 345, 346, - 347, 352, 241, 18, 19, 0, 194, 20, 0, 244, - 0, 0, 0, 247, 0, 0, 193, 0, 11, 12, - 14, 15, 16, 21, 23, 25, 26, 27, 28, 29, - 33, 34, 0, 0, 120, 13, 0, 0, 195, 24, - 38, 37, 219, 30, 0, 0, 31, 32, 35, 36, - 0, 0, 0, 120, 196, 0, 0, 0, 0, 0, - 0, 100, 102, 103, 0, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 0, 114, 115, 119, 101, - 100, 102, 103, 0, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 198, 114, 115, 119, 101, 120, - 0, 62, 0, 116, 118, 117, 0, 185, 176, 0, - 0, 61, 0, 0, 0, 62, 0, 0, 0, 0, - 0, 185, 116, 118, 117, 61, 100, 102, 103, 0, - 104, 105, 106, 86, 108, 109, 110, 111, 112, 113, - 0, 114, 115, 119, 101, 0, 0, 86, 0, 87, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 184, - 183, 0, 0, 87, 0, 0, 0, 0, 116, 118, - 117, 0, 0, 184, 183, 409, 0, 0, 0, 0, - 0, 0, 0, 0, 202, 203, 343, 344, 342, 349, - 351, 348, 350, 345, 346, 347, 352, 0, 179, 180, + 61, 363, 190, 429, 351, 436, 431, 293, 247, 201, + 98, 51, 147, 193, 369, 96, 231, 412, 413, 370, + 132, 133, 68, 130, 73, 163, 194, 131, 443, 444, + 445, 446, 134, 135, 256, 253, 254, 255, 257, 258, + 259, 129, 70, 426, 123, 425, 124, 127, 391, 342, + 157, 458, 223, 198, 447, 389, 415, 128, 126, 345, + 451, 129, 125, 197, 414, 465, 398, 138, 379, 140, + 6, 103, 105, 106, 346, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 199, 117, 118, 122, 104, + 347, 136, 343, 46, 124, 127, 389, 133, 334, 251, + 397, 200, 149, 377, 192, 128, 126, 199, 134, 129, + 125, 198, 141, 333, 420, 396, 119, 121, 120, 123, + 186, 197, 395, 200, 203, 208, 209, 210, 211, 212, + 213, 181, 376, 419, 430, 204, 204, 204, 204, 204, + 204, 204, 182, 199, 185, 227, 205, 205, 205, 205, + 205, 205, 205, 216, 219, 215, 204, 341, 214, 200, + 137, 117, 139, 122, 339, 385, 237, 205, 239, 464, + 384, 249, 226, 2, 3, 4, 5, 91, 290, 225, + 340, 123, 289, 280, 250, 383, 364, 338, 124, 127, + 284, 119, 121, 120, 275, 195, 196, 288, 218, 128, + 126, 204, 460, 129, 125, 205, 280, 278, 158, 105, + 374, 217, 205, 286, 287, 423, 243, 204, 241, 114, + 115, 124, 127, 117, 373, 122, 104, 372, 205, 222, + 143, 437, 128, 126, 124, 127, 129, 125, 65, 242, + 149, 240, 337, 142, 42, 128, 126, 418, 64, 129, + 125, 285, 252, 119, 121, 120, 365, 366, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 344, 371, 127, 367, 368, 198, 283, + 375, 124, 127, 282, 378, 128, 126, 281, 197, 129, + 203, 204, 128, 126, 135, 204, 129, 125, 198, 380, + 65, 204, 205, 144, 7, 409, 205, 408, 197, 407, + 64, 406, 205, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 202, 232, + 199, 233, 89, 156, 417, 65, 387, 405, 463, 233, + 404, 189, 102, 224, 403, 64, 200, 204, 90, 388, + 390, 10, 392, 124, 127, 393, 394, 462, 205, 402, + 461, 93, 124, 127, 128, 126, 401, 89, 129, 125, + 400, 235, 399, 128, 126, 416, 410, 129, 125, 235, + 8, 234, 236, 90, 44, 59, 204, 411, 43, 234, + 236, 92, 422, 188, 187, 1, 179, 205, 424, 155, + 428, 154, 230, 432, 433, 434, 150, 229, 74, 335, + 439, 438, 441, 440, 449, 450, 148, 435, 58, 452, + 228, 206, 207, 448, 336, 57, 296, 56, 386, 100, + 204, 69, 453, 454, 9, 9, 309, 455, 99, 55, + 457, 205, 315, 124, 127, 162, 421, 150, 97, 295, + 99, 54, 459, 53, 128, 126, 238, 148, 129, 125, + 97, 100, 153, 204, 466, 146, 52, 152, 95, 50, + 100, 311, 312, 100, 205, 313, 160, 220, 49, 161, + 151, 48, 159, 326, 47, 60, 297, 299, 301, 302, + 303, 314, 316, 319, 320, 321, 322, 323, 327, 328, + 246, 456, 298, 300, 304, 305, 306, 307, 308, 310, + 317, 332, 331, 318, 296, 348, 101, 324, 325, 329, + 330, 245, 244, 291, 309, 198, 94, 442, 248, 191, + 315, 350, 251, 294, 292, 197, 62, 295, 349, 145, + 0, 0, 353, 354, 352, 359, 361, 358, 360, 355, + 356, 357, 362, 0, 0, 0, 0, 199, 0, 311, + 312, 0, 0, 313, 0, 0, 0, 0, 0, 0, + 0, 326, 0, 200, 297, 299, 301, 302, 303, 314, + 316, 319, 320, 321, 322, 323, 327, 328, 0, 0, + 298, 300, 304, 305, 306, 307, 308, 310, 317, 332, + 331, 318, 0, 0, 0, 324, 325, 329, 330, 65, + 0, 0, 63, 91, 0, 66, 427, 0, 25, 64, + 0, 0, 221, 0, 0, 67, 0, 353, 354, 352, + 359, 361, 358, 360, 355, 356, 357, 362, 0, 0, + 0, 89, 0, 0, 0, 0, 0, 21, 22, 0, + 0, 23, 0, 0, 0, 0, 0, 90, 0, 0, + 0, 0, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 0, 0, 0, 13, + 0, 0, 16, 17, 18, 0, 27, 41, 40, 0, + 33, 0, 0, 34, 35, 71, 72, 65, 45, 0, + 63, 91, 0, 66, 0, 0, 25, 64, 0, 0, + 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, + 0, 0, 0, 0, 0, 21, 22, 0, 0, 23, + 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 0, 0, 0, 13, 0, 0, + 16, 17, 18, 0, 27, 41, 40, 0, 33, 0, + 0, 34, 35, 71, 72, 65, 0, 0, 63, 91, + 0, 66, 0, 0, 25, 64, 0, 0, 0, 0, + 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, + 0, 0, 0, 21, 22, 0, 0, 23, 0, 0, + 0, 0, 0, 90, 0, 0, 0, 0, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 0, 0, 0, 13, 0, 0, 16, 17, + 18, 0, 27, 41, 40, 0, 33, 20, 91, 34, + 35, 71, 72, 25, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 21, 22, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 11, 12, 14, + 15, 19, 24, 26, 28, 29, 30, 31, 32, 36, + 37, 0, 0, 0, 13, 0, 0, 16, 17, 18, + 0, 27, 41, 40, 0, 33, 20, 42, 34, 35, + 38, 39, 25, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 21, 22, 0, 0, 23, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 12, 14, 15, + 19, 24, 26, 28, 29, 30, 31, 32, 36, 37, + 123, 0, 0, 13, 0, 0, 16, 17, 18, 0, + 27, 41, 40, 0, 33, 0, 0, 34, 35, 38, + 39, 123, 0, 0, 0, 0, 0, 103, 105, 106, + 0, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 0, 117, 118, 122, 104, 0, 0, 103, 105, + 106, 0, 107, 108, 109, 0, 111, 112, 113, 114, + 115, 116, 382, 117, 118, 122, 104, 0, 0, 65, + 0, 123, 119, 121, 120, 189, 65, 0, 0, 64, + 0, 381, 189, 0, 0, 0, 64, 0, 0, 0, + 0, 0, 0, 119, 121, 120, 0, 0, 103, 105, + 106, 89, 107, 108, 0, 0, 111, 112, 89, 114, + 115, 116, 180, 117, 118, 122, 104, 90, 0, 65, + 0, 0, 0, 0, 90, 189, 65, 188, 187, 64, + 0, 0, 279, 0, 188, 187, 64, 123, 0, 0, + 0, 0, 0, 119, 121, 120, 0, 0, 0, 0, + 0, 89, 0, 0, 0, 206, 207, 0, 89, 0, + 0, 0, 206, 207, 103, 105, 0, 90, 0, 0, + 0, 0, 0, 0, 90, 114, 115, 188, 187, 117, + 118, 122, 104, 0, 188, 187, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 183, 184, 0, 0, 119, + 121, 120, 276, 277, } var yyPact = [...]int16{ - 55, 269, 806, 806, 657, 12, -1000, -1000, -1000, 267, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 488, - -1000, 329, -1000, 889, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -4, 27, - 222, -1000, -1000, 742, -1000, 742, 263, -1000, 172, 165, - 230, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 426, -1000, - -1000, 495, -1000, -1000, 345, 326, -1000, -1000, 31, -1000, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, 956, -1000, -1000, 176, - 942, 324, 324, 324, 324, 324, 324, 222, -52, -1000, - 266, 266, 572, -1000, 870, 717, 126, -13, -1000, 141, - 139, 324, 494, -1000, -1000, 168, 188, -1000, -1000, 417, - -1000, 189, -1000, 116, 847, 742, -1000, -46, -63, -1000, - 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, - 742, 742, 742, 742, 742, -1000, -1000, -1000, 507, 219, - 214, 213, -4, -1000, -1000, 324, -1000, 190, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 101, 101, 276, -1000, -4, - -1000, 324, 172, 165, 59, 59, -13, -13, -13, -13, - -1000, -1000, -1000, 487, -1000, -1000, 49, -1000, 889, -1000, - -1000, -1000, -1000, 739, -1000, 406, -1000, 88, -1000, -1000, - -1000, -1000, -1000, 48, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 21, 142, 13, -1000, -1000, -1000, 813, 9, 266, - 266, 266, 266, 126, 126, 569, 569, 569, 310, 935, - 569, 569, 310, 126, 126, 569, 126, 9, -1000, 162, - 160, 158, 324, -13, 108, 107, 324, 717, 94, -1000, - -1000, -1000, 179, -1000, 167, -1000, -1000, -1000, -1000, -1000, + 68, 294, 934, 934, 688, 855, -1000, -1000, -1000, 231, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 742, 324, -1000, -1000, -1000, -1000, - -1000, -1000, 53, 53, 20, 53, 155, 155, 201, 150, - -1000, -1000, 323, 322, 321, 317, 315, 298, 295, 294, - 292, 290, 281, -1000, -1000, -1000, -1000, -1000, 87, 36, - 324, 636, -1000, -1000, 643, -1000, 98, -1000, -1000, -1000, - 402, -1000, 889, 476, -1000, -1000, -1000, 53, -1000, 19, - 18, 1008, -1000, -1000, -1000, 50, 284, 284, 284, 101, - 234, 234, 50, 234, 50, -65, -1000, -1000, 233, -1000, - 324, -1000, -1000, -1000, -1000, -1000, -1000, 53, 53, -1000, - -1000, -1000, 53, -1000, -1000, -1000, -1000, -1000, -1000, 284, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 324, - 403, -1000, -1000, -1000, 217, -1000, 174, -1000, 313, -1000, - -1000, -1000, -1000, -1000, + -1000, -1000, 448, -1000, 340, -1000, 996, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 5, 18, 279, -1000, -1000, 776, -1000, 776, 164, + -1000, 228, 215, 288, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 445, -1000, -1000, 460, -1000, -1000, 397, 329, -1000, + -1000, 26, -1000, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, 1120, + -1000, -1000, 102, 326, 1077, 1077, 1077, 1077, 1077, 1077, + 279, -58, -1000, 196, 196, 600, -1000, 30, 321, 105, + -15, -1000, 157, 150, 1077, 400, -1000, -1000, 327, 335, + -1000, -1000, 436, -1000, 216, -1000, 214, 516, 776, -1000, + -47, -51, -41, -1000, 776, 776, 776, 776, 776, 776, + 776, 776, 776, 776, 776, 776, 776, 776, 776, -1000, + -1000, -1000, 1127, 272, 268, 264, 5, -1000, -1000, 1077, + -1000, 236, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 269, + 269, 176, -1000, 5, -1000, 1077, 228, 215, 233, 233, + -15, -15, -15, -15, -1000, -1000, -1000, 512, -1000, -1000, + 91, -1000, 996, -1000, -1000, -1000, -1000, 402, -1000, 404, + -1000, 162, -1000, -1000, -1000, -1000, -1000, 155, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 23, 66, 33, -1000, -1000, + -1000, 514, 167, 171, 171, 171, 196, 196, 196, 196, + 105, 105, 1133, 1133, 1133, 1067, 1017, 1133, 1133, 1067, + 105, 105, 1133, 105, 167, -1000, 212, 209, 195, 1077, + -15, 110, 81, 1077, 321, 46, -1000, -1000, -1000, 1070, + -1000, 163, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 776, 1077, -1000, -1000, -1000, -1000, + -1000, -1000, 36, 36, 22, 36, 83, 83, 98, 49, + -1000, -1000, 366, 364, 360, 353, 338, 334, 331, 305, + 303, 301, 299, -1000, 291, -67, -65, -1000, -1000, -1000, + -1000, -1000, 42, 34, 1077, 312, -1000, -1000, 240, -1000, + 112, -1000, -1000, -1000, 424, -1000, 996, 193, -1000, -1000, + -1000, 36, -1000, 19, 17, 599, -1000, -1000, -1000, 77, + 289, 289, 289, 269, 217, 217, 77, 217, 77, -71, + 32, 229, 171, 171, -1000, -1000, 53, -1000, 1077, -1000, + -1000, -1000, -1000, -1000, -1000, 36, 36, -1000, -1000, -1000, + 36, -1000, -1000, -1000, -1000, -1000, -1000, 289, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 29, -1000, + -1000, 1077, 180, -1000, -1000, -1000, 336, -1000, -1000, 147, + -1000, 44, -1000, -1000, -1000, -1000, -1000, } var yyPgo = [...]int16{ - 0, 478, 13, 463, 6, 15, 462, 371, 22, 458, - 9, 457, 14, 292, 378, 454, 16, 448, 19, 12, - 447, 443, 7, 439, 4, 5, 436, 3, 2, 10, - 435, 21, 1, 434, 433, 26, 204, 432, 422, 88, - 409, 407, 28, 406, 41, 405, 11, 403, 402, 387, - 385, 384, 379, 376, 373, 340, 0, 358, 8, 357, - 350, 342, + 0, 539, 12, 536, 7, 16, 533, 431, 22, 529, + 10, 527, 24, 351, 380, 526, 15, 523, 19, 14, + 522, 516, 8, 515, 4, 5, 501, 3, 6, 13, + 500, 26, 2, 485, 484, 23, 208, 482, 481, 479, + 93, 478, 477, 27, 476, 1, 42, 469, 11, 466, + 453, 451, 445, 439, 427, 425, 418, 385, 0, 408, + 9, 396, 395, 388, } var yyR1 = [...]int8{ - 0, 60, 60, 60, 60, 60, 60, 60, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 34, 34, 34, 34, 35, 35, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 36, 38, 38, 50, 50, - 43, 43, 43, 43, 18, 18, 18, 18, 17, 17, - 17, 4, 4, 4, 40, 42, 42, 41, 41, 41, - 51, 58, 47, 47, 48, 49, 33, 33, 33, 9, - 9, 45, 53, 53, 53, 53, 53, 53, 54, 55, - 55, 55, 44, 44, 44, 1, 1, 1, 2, 2, - 2, 2, 2, 2, 2, 14, 14, 7, 7, 7, + 0, 62, 62, 62, 62, 62, 62, 62, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 34, 34, 34, 34, 35, 35, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 36, 39, 39, 52, 52, + 44, 44, 44, 44, 37, 37, 37, 37, 37, 37, + 18, 18, 18, 18, 17, 17, 17, 4, 4, 4, + 45, 45, 41, 43, 43, 42, 42, 42, 53, 60, + 49, 49, 50, 51, 33, 33, 33, 9, 9, 47, + 55, 55, 55, 55, 55, 55, 56, 57, 57, 57, + 46, 46, 46, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 13, 13, 13, 13, 15, - 15, 15, 16, 16, 16, 16, 16, 16, 16, 61, - 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 30, 30, 30, 22, 22, 22, 22, - 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 25, 25, 26, 26, 26, 11, - 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 13, 13, 13, 13, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, + 63, 21, 21, 21, 21, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 30, 30, 30, 22, 22, 22, + 22, 23, 23, 23, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 26, 26, 26, + 11, 11, 11, 11, 3, 3, 3, 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, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 8, 8, 5, 5, 5, 5, 46, 46, 29, 29, - 31, 31, 32, 32, 28, 27, 27, 52, 10, 19, - 19, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 12, 12, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 57, + 6, 6, 6, 6, 8, 8, 5, 5, 5, 5, + 48, 48, 29, 29, 31, 31, 32, 32, 28, 27, + 27, 54, 10, 19, 19, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 12, 12, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 59, } var yyR2 = [...]int8{ @@ -636,126 +669,131 @@ var yyR2 = [...]int8{ 1, 1, 1, 3, 3, 2, 2, 2, 2, 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, 4, 2, 1, 3, 1, - 2, 1, 1, 1, 2, 3, 2, 3, 1, 2, - 3, 1, 3, 3, 2, 2, 3, 5, 3, 1, - 1, 4, 6, 5, 6, 5, 4, 3, 2, 2, - 1, 1, 3, 4, 2, 3, 1, 2, 3, 3, - 1, 3, 3, 2, 1, 2, 1, 1, 1, 1, + 1, 1, 3, 3, 1, 3, 3, 3, 5, 5, + 3, 4, 2, 1, 3, 1, 2, 1, 1, 1, + 3, 4, 2, 3, 2, 3, 1, 2, 3, 1, + 3, 3, 2, 2, 3, 5, 3, 1, 1, 4, + 6, 5, 6, 5, 4, 3, 2, 2, 1, 1, + 3, 4, 2, 3, 1, 2, 3, 3, 1, 3, + 3, 2, 1, 2, 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, 3, 4, 2, 0, 3, - 1, 2, 3, 3, 1, 3, 3, 2, 1, 2, - 0, 3, 2, 1, 1, 3, 1, 3, 4, 1, - 3, 5, 5, 1, 1, 1, 4, 3, 3, 2, - 3, 1, 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 4, 3, 3, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 3, 4, 2, 0, + 3, 1, 2, 3, 3, 1, 3, 3, 2, 1, + 2, 0, 3, 2, 1, 1, 3, 1, 3, 4, + 1, 3, 5, 5, 1, 1, 1, 4, 3, 3, + 2, 3, 1, 2, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 4, 3, 3, 1, 2, 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, 2, 1, 1, 1, 0, - 1, 1, 2, 3, 3, 4, 4, 6, 7, 4, - 1, 1, 1, 1, 2, 3, 3, 3, 3, 3, - 3, 3, 3, 6, 1, 3, + 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, + 1, 1, 1, 0, 1, 1, 2, 3, 3, 4, + 4, 6, 7, 4, 1, 1, 1, 1, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 6, 1, 3, } var yyChk = [...]int16{ - -1000, -60, 102, 103, 104, 105, 2, 10, -14, -7, - -13, 62, 63, 79, 64, 65, 66, 12, 47, 48, - 51, 67, 18, 68, 83, 69, 70, 71, 72, 73, - 87, 90, 91, 74, 75, 92, 93, 85, 84, 13, - -61, -14, 10, -39, -34, -37, -40, -45, -46, -47, - -48, -49, -51, -52, -53, -54, -55, -33, -56, -3, - 12, 19, 9, 15, 25, -8, -7, -44, 92, 93, - -12, -57, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 41, 57, 13, -55, - -13, -15, 20, -16, 12, -10, 2, 25, -21, 2, - 41, 59, 42, 43, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 56, 57, 83, 85, 84, 58, - 14, 41, 57, 53, 42, 52, 56, -35, -42, 2, - 79, 87, 15, -42, -39, -56, -39, -56, -44, 15, - 15, 15, -1, 20, -2, 12, -10, 2, 20, 7, - 2, 4, 2, 4, 24, -36, -43, -38, -50, 78, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -59, 2, -46, -8, 92, - 93, -12, -56, 68, 67, 15, -32, -9, 2, -29, - -31, 90, 91, 19, 9, 41, 57, -58, 2, -56, - -46, -8, 92, 93, -56, -56, -56, -56, -56, -56, - -42, -35, -18, 15, 2, -18, -41, 22, -39, 22, - 22, 22, 22, -56, 20, 7, 2, -5, 2, 4, - 54, 44, 55, -5, 20, -16, 25, 2, 25, 2, - -20, 5, -30, -22, 12, -29, -31, 16, -39, 82, - 86, 80, 81, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -46, 92, - 93, -12, 15, -56, 15, 15, 15, -56, 15, -29, - -29, 21, 6, 2, -17, 22, -4, -6, 25, 2, - 62, 78, 63, 79, 64, 65, 66, 80, 81, 12, - 82, 47, 48, 51, 67, 18, 68, 83, 86, 69, - 70, 71, 72, 73, 90, 91, 59, 74, 75, 92, - 93, 85, 84, 22, 7, 7, 20, -2, 25, 2, + -1000, -62, 105, 106, 107, 108, 2, 10, -14, -7, + -13, 62, 63, 79, 64, 65, 82, 83, 84, 66, + 12, 47, 48, 51, 67, 18, 68, 86, 69, 70, + 71, 72, 73, 90, 93, 94, 74, 75, 95, 96, + 88, 87, 13, -63, -14, 10, -40, -34, -38, -41, + -47, -48, -49, -50, -51, -53, -54, -55, -56, -57, + -33, -58, -3, 12, 19, 9, 15, 25, -8, -7, + -46, 95, 96, -12, -59, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 41, + 57, 13, -57, -13, -15, 20, -16, 12, -10, 2, + 25, -21, 2, 41, 59, 42, 43, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 56, 57, 86, + 88, 87, 58, 14, 41, 57, 53, 42, 52, 56, + -35, -43, 2, 79, 90, 15, -43, -40, -58, -40, + -58, -46, 15, 15, 15, -1, 20, -2, 12, -10, + 2, 20, 7, 2, 4, 2, 4, 24, -36, -37, + -44, -39, -52, 78, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -61, + 2, -48, -8, 95, 96, -12, -58, 68, 67, 15, + -32, -9, 2, -29, -31, 93, 94, 19, 9, 41, + 57, -60, 2, -58, -48, -8, 95, 96, -58, -58, + -58, -58, -58, -58, -43, -35, -18, 15, 2, -18, + -42, 22, -40, 22, 22, 22, 22, -58, 20, 7, + 2, -5, 2, 4, 54, 44, 55, -5, 20, -16, + 25, 2, 25, 2, -20, 5, -30, -22, 12, -29, + -31, 16, -40, 82, 83, 84, 85, 89, 80, 81, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -48, 95, 96, -12, 15, + -58, 15, 15, 15, -58, 15, -29, -29, 21, 6, + 2, -17, 22, -4, -6, 25, 2, 62, 78, 63, + 79, 64, 65, 66, 80, 81, 82, 83, 84, 12, + 85, 47, 48, 51, 67, 18, 68, 86, 89, 69, + 70, 71, 72, 73, 93, 94, 59, 74, 75, 95, + 96, 88, 87, 22, 7, 7, 20, -2, 25, 2, 25, 2, 26, 26, -31, 26, 41, 57, -23, 24, 17, -24, 30, 28, 29, 35, 36, 37, 33, 31, - 34, 32, 38, -18, -18, -19, -18, -19, 15, 15, - 15, -56, 22, 22, -56, 22, -58, 21, 2, 22, - 7, 2, -39, -56, -28, 19, -28, 26, -28, -22, - -22, 24, 17, 2, 17, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 22, 22, -56, 22, - 7, 21, 2, 22, -4, 22, -28, 26, 26, 17, - -24, -27, 57, -28, -32, -32, -32, -29, -25, 14, - -25, -27, -25, -27, -11, 96, 97, 98, 99, 7, - -56, -28, -28, -28, -26, -32, -56, 22, 24, 21, - 2, 22, 21, -32, + 34, 32, 38, -45, 15, -45, -45, -18, -18, -19, + -18, -19, 15, 15, 15, -58, 22, 22, -58, 22, + -60, 21, 2, 22, 7, 2, -40, -58, -28, 19, + -28, 26, -28, -22, -22, 24, 17, 2, 17, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + -48, -8, 84, 83, 22, 22, -58, 22, 7, 21, + 2, 22, -4, 22, -28, 26, 26, 17, -24, -27, + 57, -28, -32, -32, -32, -29, -25, 14, -25, -27, + -25, -27, -11, 99, 100, 101, 102, 22, -48, -45, + -45, 7, -58, -28, -28, -28, -26, -32, 22, -58, + 22, 24, 21, 2, 22, 21, -32, } var yyDef = [...]int16{ - 0, -2, 138, 138, 0, 0, 7, 6, 1, 138, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 0, - 2, -2, 3, 4, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, - 113, 246, 247, 0, 257, 0, 90, 91, 131, 132, - 0, 284, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, 240, 241, 0, 5, - 105, 0, 137, 140, 0, 144, 148, 258, 149, 153, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 0, 74, 75, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, - 0, 0, 0, 64, 0, 22, 88, -2, 89, 0, - 0, 0, 0, 94, 96, 0, 100, 104, 135, 0, - 141, 0, 147, 0, 152, 0, 45, 50, 51, 47, + 0, -2, 149, 149, 0, 0, 7, 6, 1, 149, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 0, 2, -2, 3, 4, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 0, 124, 260, 261, 0, 271, 0, 98, + 99, 142, 143, 0, 298, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, 254, + 255, 0, 5, 113, 0, 148, 151, 0, 155, 159, + 272, 160, 164, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 0, + 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 25, 26, 0, 0, 0, 72, 0, 22, 96, + -2, 97, 0, 0, 0, 0, 102, 104, 0, 108, + 112, 146, 0, 152, 0, 158, 0, 163, 0, 45, + 54, 50, 51, 47, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, + 81, 275, 0, 0, 0, 0, 284, 285, 286, 0, + 84, 0, 86, 266, 267, 87, 88, 262, 263, 0, + 0, 0, 95, 79, 287, 0, 0, 0, 289, 290, + 291, 292, 293, 294, 23, 24, 27, 0, 63, 28, + 0, 74, 76, 78, 299, 295, 296, 0, 100, 0, + 105, 0, 111, 256, 257, 258, 259, 0, 147, 150, + 153, 156, 154, 157, 162, 165, 167, 170, 174, 175, + 176, 0, 29, 0, 0, 0, 0, 0, -2, -2, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 276, 0, 0, 0, 0, + 288, 0, 0, 0, 0, 0, 264, 265, 89, 0, + 94, 0, 62, 65, 67, 68, 69, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 73, 77, 0, 101, 103, 106, 110, + 107, 109, 0, 0, 0, 0, 0, 0, 0, 0, + 180, 182, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 55, 0, 56, 57, 48, 49, 52, + 274, 53, 0, 0, 0, 0, 277, 278, 0, 85, + 0, 91, 93, 60, 0, 66, 75, 0, 166, 268, + 168, 0, 171, 0, 0, 0, 178, 183, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 72, 73, 261, 0, 0, - 0, 0, 270, 271, 272, 0, 76, 0, 78, 252, - 253, 79, 80, 248, 249, 0, 0, 0, 87, 71, - 273, 0, 0, 0, 275, 276, 277, 278, 279, 280, - 23, 24, 27, 0, 57, 28, 0, 66, 68, 70, - 285, 281, 282, 0, 92, 0, 97, 0, 103, 242, - 243, 244, 245, 0, 136, 139, 142, 145, 143, 146, - 151, 154, 156, 159, 163, 164, 165, 0, 29, 0, - 0, -2, -2, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 262, 0, - 0, 0, 0, 274, 0, 0, 0, 0, 0, 250, - 251, 81, 0, 86, 0, 56, 59, 61, 62, 63, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 65, 69, 0, 93, 95, 98, 102, - 99, 101, 0, 0, 0, 0, 0, 0, 0, 0, - 169, 171, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 48, 49, 52, 260, 53, 0, 0, - 0, 0, 263, 264, 0, 77, 0, 83, 85, 54, - 0, 60, 67, 0, 155, 254, 157, 0, 160, 0, - 0, 0, 167, 172, 168, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 265, 266, 0, 269, - 0, 82, 84, 55, 58, 283, 158, 0, 0, 166, - 170, 173, 0, 256, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 189, 190, 191, 192, 0, - 0, 161, 162, 255, 0, 187, 0, 267, 0, 185, - 188, 268, 184, 186, + 0, 0, 0, 0, 279, 280, 0, 283, 0, 90, + 92, 61, 64, 297, 169, 0, 0, 177, 181, 184, + 0, 270, 185, 186, 187, 188, 189, 0, 190, 191, + 192, 193, 194, 200, 201, 202, 203, 70, 0, 58, + 59, 0, 0, 172, 173, 269, 0, 198, 71, 0, + 281, 0, 196, 199, 282, 195, 197, } var yyTok1 = [...]int8{ @@ -773,7 +811,7 @@ var yyTok2 = [...]int8{ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, + 102, 103, 104, 105, 106, 107, 108, 109, } var yyTok3 = [...]int8{ @@ -1298,44 +1336,83 @@ yydefault: yyVAL.node.(*BinaryExpr).VectorMatching.Card = CardOneToMany yyVAL.node.(*BinaryExpr).VectorMatching.Include = yyDollar[3].strings } - case 54: + case 55: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.node = yyDollar[1].node + fill := yyDollar[3].node.(*NumberLiteral).Val + yyVAL.node.(*BinaryExpr).VectorMatching.FillValues.LHS = &fill + yyVAL.node.(*BinaryExpr).VectorMatching.FillValues.RHS = &fill + } + case 56: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.node = yyDollar[1].node + fill := yyDollar[3].node.(*NumberLiteral).Val + yyVAL.node.(*BinaryExpr).VectorMatching.FillValues.LHS = &fill + } + case 57: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.node = yyDollar[1].node + fill := yyDollar[3].node.(*NumberLiteral).Val + yyVAL.node.(*BinaryExpr).VectorMatching.FillValues.RHS = &fill + } + case 58: + yyDollar = yyS[yypt-5 : yypt+1] + { + yyVAL.node = yyDollar[1].node + fill_left := yyDollar[3].node.(*NumberLiteral).Val + fill_right := yyDollar[5].node.(*NumberLiteral).Val + yyVAL.node.(*BinaryExpr).VectorMatching.FillValues.LHS = &fill_left + yyVAL.node.(*BinaryExpr).VectorMatching.FillValues.RHS = &fill_right + } + case 59: + yyDollar = yyS[yypt-5 : yypt+1] + { + fill_right := yyDollar[3].node.(*NumberLiteral).Val + fill_left := yyDollar[5].node.(*NumberLiteral).Val + yyVAL.node.(*BinaryExpr).VectorMatching.FillValues.LHS = &fill_left + yyVAL.node.(*BinaryExpr).VectorMatching.FillValues.RHS = &fill_right + } + case 60: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.strings = yyDollar[2].strings } - case 55: + case 61: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.strings = yyDollar[2].strings } - case 56: + case 62: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.strings = []string{} } - case 57: + case 63: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("grouping opts", "\"(\"") yyVAL.strings = nil } - case 58: + case 64: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.strings = append(yyDollar[1].strings, yyDollar[3].item.Val) } - case 59: + case 65: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.strings = []string{yyDollar[1].item.Val} } - case 60: + case 66: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("grouping opts", "\",\" or \")\"") yyVAL.strings = yyDollar[1].strings } - case 61: + case 67: yyDollar = yyS[yypt-1 : yypt+1] { if !model.UTF8Validation.IsValidLabelName(yyDollar[1].item.Val) { @@ -1343,7 +1420,7 @@ yydefault: } yyVAL.item = yyDollar[1].item } - case 62: + case 68: yyDollar = yyS[yypt-1 : yypt+1] { unquoted := yylex.(*parser).unquoteString(yyDollar[1].item.Val) @@ -1354,13 +1431,28 @@ yydefault: yyVAL.item.Pos++ yyVAL.item.Val = unquoted } - case 63: + case 69: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("grouping opts", "label") yyVAL.item = Item{} } - case 64: + case 70: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.node = yyDollar[2].node.(*NumberLiteral) + } + case 71: + yyDollar = yyS[yypt-4 : yypt+1] + { + nl := yyDollar[3].node.(*NumberLiteral) + if yyDollar[2].item.Typ == SUB { + nl.Val *= -1 + } + nl.PosRange.Start = yyDollar[2].item.Pos + yyVAL.node = nl + } + case 72: yyDollar = yyS[yypt-2 : yypt+1] { fn, exist := getFunction(yyDollar[1].item.Val, yylex.(*parser).functions) @@ -1379,38 +1471,38 @@ yydefault: }, } } - case 65: + case 73: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = yyDollar[2].node } - case 66: + case 74: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.node = Expressions{} } - case 67: + case 75: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = append(yyDollar[1].node.(Expressions), yyDollar[3].node.(Expr)) } - case 68: + case 76: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = Expressions{yyDollar[1].node.(Expr)} } - case 69: + case 77: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).addParseErrf(yyDollar[2].item.PositionRange(), "trailing commas not allowed in function call args") yyVAL.node = yyDollar[1].node } - case 70: + case 78: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &ParenExpr{Expr: yyDollar[2].node.(Expr), PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item)} } - case 71: + case 79: yyDollar = yyS[yypt-1 : yypt+1] { if numLit, ok := yyDollar[1].node.(*NumberLiteral); ok { @@ -1424,7 +1516,7 @@ yydefault: } yyVAL.node = yyDollar[1].node } - case 72: + case 80: yyDollar = yyS[yypt-3 : yypt+1] { if numLit, ok := yyDollar[3].node.(*NumberLiteral); ok { @@ -1435,41 +1527,41 @@ yydefault: yylex.(*parser).addOffsetExpr(yyDollar[1].node, yyDollar[3].node.(*DurationExpr)) yyVAL.node = yyDollar[1].node } - case 73: + case 81: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("offset", "number, duration, step(), or range()") yyVAL.node = yyDollar[1].node } - case 74: + case 82: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).setAnchored(yyDollar[1].node) } - case 75: + case 83: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).setSmoothed(yyDollar[1].node) } - case 76: + case 84: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).setTimestamp(yyDollar[1].node, yyDollar[3].float) yyVAL.node = yyDollar[1].node } - case 77: + case 85: yyDollar = yyS[yypt-5 : yypt+1] { yylex.(*parser).setAtModifierPreprocessor(yyDollar[1].node, yyDollar[3].item) yyVAL.node = yyDollar[1].node } - case 78: + case 86: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("@", "timestamp") yyVAL.node = yyDollar[1].node } - case 81: + case 89: yyDollar = yyS[yypt-4 : yypt+1] { var errMsg string @@ -1499,7 +1591,7 @@ yydefault: EndPos: yylex.(*parser).lastClosing, } } - case 82: + case 90: yyDollar = yyS[yypt-6 : yypt+1] { var rangeNl time.Duration @@ -1521,7 +1613,7 @@ yydefault: EndPos: yyDollar[6].item.Pos + 1, } } - case 83: + case 91: yyDollar = yyS[yypt-5 : yypt+1] { var rangeNl time.Duration @@ -1536,31 +1628,31 @@ yydefault: EndPos: yyDollar[5].item.Pos + 1, } } - case 84: + case 92: yyDollar = yyS[yypt-6 : yypt+1] { yylex.(*parser).unexpected("subquery selector", "\"]\"") yyVAL.node = yyDollar[1].node } - case 85: + case 93: yyDollar = yyS[yypt-5 : yypt+1] { yylex.(*parser).unexpected("subquery selector", "number, duration, step(), range(), or \"]\"") yyVAL.node = yyDollar[1].node } - case 86: + case 94: yyDollar = yyS[yypt-4 : yypt+1] { yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"") yyVAL.node = yyDollar[1].node } - case 87: + case 95: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("subquery or range selector", "number, duration, step(), or range()") yyVAL.node = yyDollar[1].node } - case 88: + case 96: yyDollar = yyS[yypt-2 : yypt+1] { if nl, ok := yyDollar[2].node.(*NumberLiteral); ok { @@ -1573,7 +1665,7 @@ yydefault: yyVAL.node = &UnaryExpr{Op: yyDollar[1].item.Typ, Expr: yyDollar[2].node.(Expr), StartPos: yyDollar[1].item.Pos} } } - case 89: + case 97: yyDollar = yyS[yypt-2 : yypt+1] { vs := yyDollar[2].node.(*VectorSelector) @@ -1582,7 +1674,7 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 90: + case 98: yyDollar = yyS[yypt-1 : yypt+1] { vs := &VectorSelector{ @@ -1593,14 +1685,14 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 91: + case 99: yyDollar = yyS[yypt-1 : yypt+1] { vs := yyDollar[1].node.(*VectorSelector) yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 92: + case 100: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1608,7 +1700,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item), } } - case 93: + case 101: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1616,7 +1708,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[4].item), } } - case 94: + case 102: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1624,7 +1716,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[2].item), } } - case 95: + case 103: yyDollar = yyS[yypt-3 : yypt+1] { if yyDollar[1].matchers != nil { @@ -1633,144 +1725,144 @@ yydefault: yyVAL.matchers = yyDollar[1].matchers } } - case 96: + case 104: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher} } - case 97: + case 105: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") yyVAL.matchers = yyDollar[1].matchers } - case 98: + case 106: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) } - case 99: + case 107: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) } - case 100: + case 108: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.matcher = yylex.(*parser).newMetricNameMatcher(yyDollar[1].item) } - case 101: + case 109: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label matching", "string") yyVAL.matcher = nil } - case 102: + case 110: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label matching", "string") yyVAL.matcher = nil } - case 103: + case 111: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label matching", "label matching operator") yyVAL.matcher = nil } - case 104: + case 112: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("label matching", "identifier or \"}\"") yyVAL.matcher = nil } - case 105: + case 113: yyDollar = yyS[yypt-2 : yypt+1] { b := labels.NewBuilder(yyDollar[2].labels) b.Set(labels.MetricName, yyDollar[1].item.Val) yyVAL.labels = b.Labels() } - case 106: + case 114: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.labels = yyDollar[1].labels } - case 135: + case 146: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.labels = labels.New(yyDollar[2].lblList...) } - case 136: + case 147: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.labels = labels.New(yyDollar[2].lblList...) } - case 137: + case 148: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.labels = labels.New() } - case 138: + case 149: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.labels = labels.New() } - case 139: + case 150: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.lblList = append(yyDollar[1].lblList, yyDollar[3].label) } - case 140: + case 151: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.lblList = []labels.Label{yyDollar[1].label} } - case 141: + case 152: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label set", "\",\" or \"}\"") yyVAL.lblList = yyDollar[1].lblList } - case 142: + case 153: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} } - case 143: + case 154: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} } - case 144: + case 155: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.label = labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val} } - case 145: + case 156: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label set", "string") yyVAL.label = labels.Label{} } - case 146: + case 157: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("label set", "string") yyVAL.label = labels.Label{} } - case 147: + case 158: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label set", "\"=\"") yyVAL.label = labels.Label{} } - case 148: + case 159: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("label set", "identifier or \"}\"") yyVAL.label = labels.Label{} } - case 149: + case 160: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).generatedParserResult = &seriesDescription{ @@ -1778,33 +1870,33 @@ yydefault: values: yyDollar[2].series, } } - case 150: + case 161: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.series = []SequenceValue{} } - case 151: + case 162: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...) } - case 152: + case 163: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.series = yyDollar[1].series } - case 153: + case 164: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("series values", "") yyVAL.series = nil } - case 154: + case 165: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Omitted: true}} } - case 155: + case 166: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1812,12 +1904,12 @@ yydefault: yyVAL.series = append(yyVAL.series, SequenceValue{Omitted: true}) } } - case 156: + case 167: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Value: yyDollar[1].float}} } - case 157: + case 168: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1826,7 +1918,7 @@ yydefault: yyVAL.series = append(yyVAL.series, SequenceValue{Value: yyDollar[1].float}) } } - case 158: + case 169: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1836,12 +1928,12 @@ yydefault: yyDollar[1].float += yyDollar[2].float } } - case 159: + case 170: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Histogram: yyDollar[1].histogram}} } - case 160: + case 171: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1851,7 +1943,7 @@ yydefault: //$1 += $2 } } - case 161: + case 172: yyDollar = yyS[yypt-5 : yypt+1] { val, err := yylex.(*parser).histogramsIncreaseSeries(yyDollar[1].histogram, yyDollar[3].histogram, yyDollar[5].uint) @@ -1860,7 +1952,7 @@ yydefault: } yyVAL.series = val } - case 162: + case 173: yyDollar = yyS[yypt-5 : yypt+1] { val, err := yylex.(*parser).histogramsDecreaseSeries(yyDollar[1].histogram, yyDollar[3].histogram, yyDollar[5].uint) @@ -1869,7 +1961,7 @@ yydefault: } yyVAL.series = val } - case 163: + case 174: yyDollar = yyS[yypt-1 : yypt+1] { if yyDollar[1].item.Val != "stale" { @@ -1877,130 +1969,130 @@ yydefault: } yyVAL.float = math.Float64frombits(value.StaleNaN) } - case 166: + case 177: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) } - case 167: + case 178: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) } - case 168: + case 179: yyDollar = yyS[yypt-3 : yypt+1] { m := yylex.(*parser).newMap() yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) } - case 169: + case 180: yyDollar = yyS[yypt-2 : yypt+1] { m := yylex.(*parser).newMap() yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) } - case 170: + case 181: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = *(yylex.(*parser).mergeMaps(&yyDollar[1].descriptors, &yyDollar[3].descriptors)) } - case 171: + case 182: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.descriptors = yyDollar[1].descriptors } - case 172: + case 183: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("histogram description", "histogram description key, e.g. buckets:[5 10 7]") } - case 173: + case 184: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["schema"] = yyDollar[3].int } - case 174: + case 185: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["sum"] = yyDollar[3].float } - case 175: + case 186: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["count"] = yyDollar[3].float } - case 176: + case 187: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["z_bucket"] = yyDollar[3].float } - case 177: + case 188: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["z_bucket_w"] = yyDollar[3].float } - case 178: + case 189: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["custom_values"] = yyDollar[3].bucket_set } - case 179: + case 190: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["buckets"] = yyDollar[3].bucket_set } - case 180: + case 191: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["offset"] = yyDollar[3].int } - case 181: + case 192: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["n_buckets"] = yyDollar[3].bucket_set } - case 182: + case 193: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["n_offset"] = yyDollar[3].int } - case 183: + case 194: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() yyVAL.descriptors["counter_reset_hint"] = yyDollar[3].item } - case 184: + case 195: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.bucket_set = yyDollar[2].bucket_set } - case 185: + case 196: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.bucket_set = yyDollar[2].bucket_set } - case 186: + case 197: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.bucket_set = append(yyDollar[1].bucket_set, yyDollar[3].float) } - case 187: + case 198: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.bucket_set = []float64{yyDollar[1].float} } - case 246: + case 260: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &NumberLiteral{ @@ -2008,7 +2100,7 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 247: + case 261: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -2023,12 +2115,12 @@ yydefault: Duration: true, } } - case 248: + case 262: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val) } - case 249: + case 263: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -2039,17 +2131,17 @@ yydefault: } yyVAL.float = dur.Seconds() } - case 250: + case 264: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.float = yyDollar[2].float } - case 251: + case 265: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.float = -yyDollar[2].float } - case 254: + case 268: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -2058,17 +2150,17 @@ yydefault: yylex.(*parser).addParseErrf(yyDollar[1].item.PositionRange(), "invalid repetition in series values: %s", err) } } - case 255: + case 269: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.int = -int64(yyDollar[2].uint) } - case 256: + case 270: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.int = int64(yyDollar[1].uint) } - case 257: + case 271: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &StringLiteral{ @@ -2076,7 +2168,7 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 258: + case 272: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.item = Item{ @@ -2085,12 +2177,12 @@ yydefault: Val: yylex.(*parser).unquoteString(yyDollar[1].item.Val), } } - case 259: + case 273: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.strings = nil } - case 261: + case 275: yyDollar = yyS[yypt-1 : yypt+1] { nl := yyDollar[1].node.(*NumberLiteral) @@ -2101,7 +2193,7 @@ yydefault: } yyVAL.node = nl } - case 262: + case 276: yyDollar = yyS[yypt-2 : yypt+1] { nl := yyDollar[2].node.(*NumberLiteral) @@ -2116,7 +2208,7 @@ yydefault: nl.PosRange.Start = yyDollar[1].item.Pos yyVAL.node = nl } - case 263: + case 277: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2125,7 +2217,7 @@ yydefault: EndPos: yyDollar[3].item.PositionRange().End, } } - case 264: + case 278: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2134,7 +2226,7 @@ yydefault: EndPos: yyDollar[3].item.PositionRange().End, } } - case 265: + case 279: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2147,7 +2239,7 @@ yydefault: StartPos: yyDollar[1].item.Pos, } } - case 266: + case 280: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2160,7 +2252,7 @@ yydefault: StartPos: yyDollar[1].item.Pos, } } - case 267: + case 281: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2171,7 +2263,7 @@ yydefault: RHS: yyDollar[5].node.(Expr), } } - case 268: + case 282: yyDollar = yyS[yypt-7 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2187,7 +2279,7 @@ yydefault: }, } } - case 269: + case 283: yyDollar = yyS[yypt-4 : yypt+1] { de := yyDollar[3].node.(*DurationExpr) @@ -2202,7 +2294,7 @@ yydefault: } yyVAL.node = yyDollar[3].node } - case 273: + case 287: yyDollar = yyS[yypt-1 : yypt+1] { nl := yyDollar[1].node.(*NumberLiteral) @@ -2213,7 +2305,7 @@ yydefault: } yyVAL.node = nl } - case 274: + case 288: yyDollar = yyS[yypt-2 : yypt+1] { switch expr := yyDollar[2].node.(type) { @@ -2246,25 +2338,25 @@ yydefault: break } } - case 275: + case 289: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: ADD, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 276: + case 290: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: SUB, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 277: + case 291: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: MUL, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 278: + case 292: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) @@ -2275,7 +2367,7 @@ yydefault: } yyVAL.node = &DurationExpr{Op: DIV, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 279: + case 293: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) @@ -2286,13 +2378,13 @@ yydefault: } yyVAL.node = &DurationExpr{Op: MOD, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 280: + case 294: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[1].node.(Expr)) yyVAL.node = &DurationExpr{Op: POW, LHS: yyDollar[1].node.(Expr), RHS: yyDollar[3].node.(Expr)} } - case 281: + case 295: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2301,7 +2393,7 @@ yydefault: EndPos: yyDollar[3].item.PositionRange().End, } } - case 282: + case 296: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2310,7 +2402,7 @@ yydefault: EndPos: yyDollar[3].item.PositionRange().End, } } - case 283: + case 297: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.node = &DurationExpr{ @@ -2321,7 +2413,7 @@ yydefault: RHS: yyDollar[5].node.(Expr), } } - case 285: + case 299: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).experimentalDurationExpr(yyDollar[2].node.(Expr)) diff --git a/promql/parser/lex.go b/promql/parser/lex.go index b3a82dc0c6..7149985767 100644 --- a/promql/parser/lex.go +++ b/promql/parser/lex.go @@ -137,6 +137,9 @@ var key = map[string]ItemType{ "ignoring": IGNORING, "group_left": GROUP_LEFT, "group_right": GROUP_RIGHT, + "fill": FILL, + "fill_left": FILL_LEFT, + "fill_right": FILL_RIGHT, "bool": BOOL, // Preprocessors. @@ -1083,6 +1086,17 @@ Loop: word := l.input[l.start:l.pos] switch kw, ok := key[strings.ToLower(word)]; { case ok: + // For fill/fill_left/fill_right, only treat as keyword if followed by '(' + // This allows using these as metric names (e.g., "fill + fill"). + // This could be done for other keywords as well, but for the new fill + // modifiers this is especially important so we don't break any existing + // queries. + if kw == FILL || kw == FILL_LEFT || kw == FILL_RIGHT { + if !l.peekFollowedByLeftParen() { + l.emit(IDENTIFIER) + break Loop + } + } l.emit(kw) case !strings.Contains(word, ":"): l.emit(IDENTIFIER) @@ -1098,6 +1112,23 @@ Loop: return lexStatements } +// peekFollowedByLeftParen checks if the next non-whitespace character is '('. +// This is used for context-sensitive keywords like fill/fill_left/fill_right +// that should only be treated as keywords when followed by '('. +func (l *Lexer) peekFollowedByLeftParen() bool { + pos := l.pos + for { + if int(pos) >= len(l.input) { + return false + } + r, w := utf8.DecodeRuneInString(l.input[pos:]) + if !isSpace(r) { + return r == '(' + } + pos += posrange.Pos(w) + } +} + func isSpace(r rune) bool { return r == ' ' || r == '\t' || r == '\n' || r == '\r' } diff --git a/promql/parser/parse.go b/promql/parser/parse.go index 817e0d02d9..a872706364 100644 --- a/promql/parser/parse.go +++ b/promql/parser/parse.go @@ -768,6 +768,9 @@ func (p *parser) checkAST(node Node) (typ ValueType) { if len(n.VectorMatching.MatchingLabels) > 0 { p.addParseErrf(n.PositionRange(), "vector matching only allowed between instant vectors") } + if n.VectorMatching.FillValues.LHS != nil || n.VectorMatching.FillValues.RHS != nil { + p.addParseErrf(n.PositionRange(), "filling in missing series only allowed between instant vectors") + } n.VectorMatching = nil case n.Op.IsSetOperator(): // Both operands are Vectors. if n.VectorMatching.Card == CardOneToMany || n.VectorMatching.Card == CardManyToOne { @@ -776,6 +779,9 @@ func (p *parser) checkAST(node Node) (typ ValueType) { if n.VectorMatching.Card != CardManyToMany { p.addParseErrf(n.PositionRange(), "set operations must always be many-to-many") } + if n.VectorMatching.FillValues.LHS != nil || n.VectorMatching.FillValues.RHS != nil { + p.addParseErrf(n.PositionRange(), "filling in missing series not allowed for set operators") + } } if (lt == ValueTypeScalar || rt == ValueTypeScalar) && n.Op.IsSetOperator() { diff --git a/promql/parser/printer.go b/promql/parser/printer.go index 01e2c46c1b..44ca15e532 100644 --- a/promql/parser/printer.go +++ b/promql/parser/printer.go @@ -172,6 +172,19 @@ func (node *BinaryExpr) getMatchingStr() string { b.WriteString(")") matching += b.String() } + + if vm.FillValues.LHS != nil || vm.FillValues.RHS != nil { + if vm.FillValues.LHS == vm.FillValues.RHS { + matching += fmt.Sprintf(" fill (%v)", *vm.FillValues.LHS) + } else { + if vm.FillValues.LHS != nil { + matching += fmt.Sprintf(" fill_left (%v)", *vm.FillValues.LHS) + } + if vm.FillValues.RHS != nil { + matching += fmt.Sprintf(" fill_right (%v)", *vm.FillValues.RHS) + } + } + } } return matching } diff --git a/promql/parser/printer_test.go b/promql/parser/printer_test.go index 4499fa7860..a5f254527e 100644 --- a/promql/parser/printer_test.go +++ b/promql/parser/printer_test.go @@ -113,6 +113,26 @@ func TestExprString(t *testing.T) { in: `a - ignoring() group_left c`, out: `a - ignoring () group_left () c`, }, + { + in: `a + fill(-23) b`, + out: `a + fill (-23) b`, + }, + { + in: `a + fill_left(-23) b`, + out: `a + fill_left (-23) b`, + }, + { + in: `a + fill_right(42) b`, + out: `a + fill_right (42) b`, + }, + { + in: `a + fill_left(-23) fill_right(42) b`, + out: `a + fill_left (-23) fill_right (42) b`, + }, + { + in: `a + on(b) group_left fill(-23) c`, + out: `a + on (b) group_left () fill (-23) c`, + }, { in: `up > bool 0`, }, diff --git a/web/api/v1/translate_ast.go b/web/api/v1/translate_ast.go index 3cce0583f9..3c2bc09943 100644 --- a/web/api/v1/translate_ast.go +++ b/web/api/v1/translate_ast.go @@ -47,6 +47,10 @@ func translateAST(node parser.Expr) any { "labels": sanitizeList(m.MatchingLabels), "on": m.On, "include": sanitizeList(m.Include), + "fillValues": map[string]*float64{ + "lhs": m.FillValues.LHS, + "rhs": m.FillValues.RHS, + }, } } diff --git a/web/ui/mantine-ui/src/pages/query/ExplainViews/BinaryExpr/VectorVector.tsx b/web/ui/mantine-ui/src/pages/query/ExplainViews/BinaryExpr/VectorVector.tsx index e70b7a3f3e..5c10357561 100644 --- a/web/ui/mantine-ui/src/pages/query/ExplainViews/BinaryExpr/VectorVector.tsx +++ b/web/ui/mantine-ui/src/pages/query/ExplainViews/BinaryExpr/VectorVector.tsx @@ -8,6 +8,7 @@ import { MatchErrorType, computeVectorVectorBinOp, filteredSampleValue, + MaybeFilledInstantSample, } from "../../../../promql/binOp"; import { formatNode, labelNameList } from "../../../../promql/format"; import { @@ -177,11 +178,10 @@ const explanationText = (node: BinaryExpr): React.ReactNode => { ) : ( - - group_{manySide}({labelNameList(matching.include)}) - - : {matching.card} match. Each series from the {oneSide}-hand side is - allowed to match with multiple series from the {manySide}-hand side. + group_{manySide} + ({labelNameList(matching.include)}) : {matching.card} match. Each + series from the {oneSide}-hand side is allowed to match with + multiple series from the {manySide}-hand side. {matching.include.length !== 0 && ( <> {" "} @@ -192,6 +192,55 @@ const explanationText = (node: BinaryExpr): React.ReactNode => { )} )} + {(matching.fillValues.lhs !== null || + matching.fillValues.rhs !== null) && + (matching.fillValues.lhs === matching.fillValues.rhs ? ( + + fill( + + {matching.fillValues.lhs} + + ) : For series on either side missing a match, fill in the sample + value{" "} + + {matching.fillValues.lhs} + + . + + ) : ( + <> + {matching.fillValues.lhs !== null && ( + + fill_left( + + {matching.fillValues.lhs} + + ) : For series on the left-hand side missing a match, fill in + the sample value{" "} + + {matching.fillValues.lhs} + + . + + )} + + {matching.fillValues.rhs !== null && ( + + fill_right + ( + + {matching.fillValues.rhs} + + ) : For series on the right-hand side missing a match, fill in + the sample value{" "} + + {matching.fillValues.rhs} + + . + + )} + + ))} {node.bool && ( bool: Instead of @@ -239,7 +288,12 @@ const explainError = ( matching: { ...(binOp.matching ? binOp.matching - : { labels: [], on: false, include: [] }), + : { + labels: [], + on: false, + include: [], + fillValues: { lhs: null, rhs: null }, + }), card: err.dupeSide === "left" ? vectorMatchCardinality.manyToOne @@ -403,7 +457,7 @@ const VectorVectorBinaryExprExplainView: FC< ); const matchGroupTable = ( - series: InstantSample[], + series: MaybeFilledInstantSample[], seriesCount: number, color: string, colorOffset?: number @@ -458,6 +512,11 @@ const VectorVectorBinaryExprExplainView: FC< )} format={true} /> + {s.filled && ( + + no match, filling in default value + + )} {showSampleValues && ( diff --git a/web/ui/mantine-ui/src/promql/ast.ts b/web/ui/mantine-ui/src/promql/ast.ts index 94872c6db0..9f8c5cb102 100644 --- a/web/ui/mantine-ui/src/promql/ast.ts +++ b/web/ui/mantine-ui/src/promql/ast.ts @@ -104,11 +104,16 @@ export interface LabelMatcher { value: string; } +export interface FillValues { + lhs: number | null; + rhs: number | null; +} export interface VectorMatching { card: vectorMatchCardinality; labels: string[]; on: boolean; include: string[]; + fillValues: FillValues; } export type StartOrEnd = "start" | "end" | null; diff --git a/web/ui/mantine-ui/src/promql/binOp.test.ts b/web/ui/mantine-ui/src/promql/binOp.test.ts index 72ef16947b..9c5d59a94c 100644 --- a/web/ui/mantine-ui/src/promql/binOp.test.ts +++ b/web/ui/mantine-ui/src/promql/binOp.test.ts @@ -81,6 +81,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -247,6 +248,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1", "label2"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -413,6 +415,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: ["same"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -579,6 +582,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricB, rhs: testMetricC, @@ -701,6 +705,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricB, rhs: testMetricC, @@ -791,6 +796,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricB, rhs: testMetricC, @@ -905,6 +911,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricC, rhs: testMetricB, @@ -1019,6 +1026,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricC, rhs: testMetricB, @@ -1107,6 +1115,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -1223,6 +1232,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -1409,6 +1419,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -1596,6 +1607,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -1763,6 +1775,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -1929,6 +1942,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -2022,6 +2036,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricB, rhs: testMetricC, @@ -2105,6 +2120,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricB, rhs: testMetricC, @@ -2156,6 +2172,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA, rhs: testMetricB, @@ -2342,6 +2359,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA.slice(0, 3), rhs: testMetricB.slice(1, 4), @@ -2474,6 +2492,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA.slice(0, 3), rhs: testMetricB.slice(1, 4), @@ -2568,6 +2587,7 @@ const testCases: TestCase[] = [ on: true, include: [], labels: ["label1"], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA.slice(0, 3), rhs: testMetricB.slice(1, 4), @@ -2700,6 +2720,7 @@ const testCases: TestCase[] = [ on: false, include: [], labels: [], + fillValues: { lhs: null, rhs: null }, }, lhs: testMetricA.slice(0, 3), rhs: testMetricB.slice(1, 4), @@ -2886,6 +2907,7 @@ describe("binOp", () => { on: true, labels: ["label1"], include: [], + fillValues: { lhs: null, rhs: null }, }; const result = resultMetric(lhs, rhs, op, matching); @@ -2911,6 +2933,7 @@ describe("binOp", () => { on: true, labels: ["label1"], include: [], + fillValues: { lhs: null, rhs: null }, }; const result = resultMetric(lhs, rhs, op, matching); @@ -2931,6 +2954,7 @@ describe("binOp", () => { on: true, labels: ["label1"], include: ["label2"], + fillValues: { lhs: null, rhs: null }, }; const result = resultMetric(lhs, rhs, op, matching); diff --git a/web/ui/mantine-ui/src/promql/binOp.ts b/web/ui/mantine-ui/src/promql/binOp.ts index dbfa64be2c..f583bf81bb 100644 --- a/web/ui/mantine-ui/src/promql/binOp.ts +++ b/web/ui/mantine-ui/src/promql/binOp.ts @@ -45,13 +45,18 @@ export type VectorMatchError = | MultipleMatchesOnBothSidesError | MultipleMatchesOnOneSideError; +export type MaybeFilledInstantSample = InstantSample & { + // If the sample was filled in via a fill(...) modifier, this is true. + filled?: boolean; +}; + // A single match group as produced by a vector-to-vector binary operation, with all of its // left-hand side and right-hand side series, as well as a result and error, if applicable. export type BinOpMatchGroup = { groupLabels: Metric; - rhs: InstantSample[]; + rhs: MaybeFilledInstantSample[]; rhsCount: number; // Number of samples before applying limits. - lhs: InstantSample[]; + lhs: MaybeFilledInstantSample[]; lhsCount: number; // Number of samples before applying limits. result: { sample: InstantSample; @@ -338,6 +343,26 @@ export const computeVectorVectorBinOp = ( groups[sig].lhsCount++; }); + // Check for any LHS / RHS with no series and fill in default values, if specified. + Object.values(groups).forEach((mg) => { + if (mg.lhs.length === 0 && matching.fillValues.lhs !== null) { + mg.lhs.push({ + metric: {}, + value: [0, formatPrometheusFloat(matching.fillValues.lhs as number)], + filled: true, + }); + mg.lhsCount = 1; + } + if (mg.rhs.length === 0 && matching.fillValues.rhs !== null) { + mg.rhs.push({ + metric: {}, + value: [0, formatPrometheusFloat(matching.fillValues.rhs as number)], + filled: true, + }); + mg.rhsCount = 1; + } + }); + // Annotate the match groups with errors (if any) and populate the results. Object.values(groups).forEach((mg) => { switch (matching.card) { diff --git a/web/ui/mantine-ui/src/promql/format.tsx b/web/ui/mantine-ui/src/promql/format.tsx index 75b1965b35..8602c65a82 100644 --- a/web/ui/mantine-ui/src/promql/format.tsx +++ b/web/ui/mantine-ui/src/promql/format.tsx @@ -265,6 +265,7 @@ const formatNodeInternal = ( case nodeType.binaryExpr: { let matching = <>; let grouping = <>; + let fill = <>; const vm = node.matching; if (vm !== null) { if ( @@ -305,6 +306,45 @@ const formatNodeInternal = ( ); } + + const lfill = vm.fillValues.lhs; + const rfill = vm.fillValues.rhs; + if (lfill !== null || rfill !== null) { + if (lfill === rfill) { + fill = ( + <> + {" "} + fill + ( + {lfill} + ) + + ); + } else { + fill = ( + <> + {lfill !== null && ( + <> + {" "} + fill_left + ( + {lfill} + ) + + )} + {rfill !== null && ( + <> + {" "} + fill_right + ( + {rfill} + ) + + )} + + ); + } + } } return ( @@ -327,7 +367,8 @@ const formatNodeInternal = ( )} {matching} - {grouping}{" "} + {grouping} + {fill}{" "} {showChildren && formatNode( maybeParenthesizeBinopChild(node.op, node.rhs), diff --git a/web/ui/mantine-ui/src/promql/serialize.ts b/web/ui/mantine-ui/src/promql/serialize.ts index 584e1ae9ff..50c32c49e4 100644 --- a/web/ui/mantine-ui/src/promql/serialize.ts +++ b/web/ui/mantine-ui/src/promql/serialize.ts @@ -135,6 +135,7 @@ const serializeNode = ( case nodeType.binaryExpr: { let matching = ""; let grouping = ""; + let fill = ""; const vm = node.matching; if (vm !== null) { if ( @@ -152,11 +153,26 @@ const serializeNode = ( ) { grouping = ` group_${vm.card === vectorMatchCardinality.manyToOne ? "left" : "right"}(${labelNameList(vm.include)})`; } + + const lfill = vm.fillValues.lhs; + const rfill = vm.fillValues.rhs; + if (lfill !== null || rfill !== null) { + if (lfill === rfill) { + fill = ` fill(${lfill})`; + } else { + if (lfill !== null) { + fill += ` fill_left(${lfill})`; + } + if (rfill !== null) { + fill += ` fill_right(${rfill})`; + } + } + } } return `${serializeNode(maybeParenthesizeBinopChild(node.op, node.lhs), childIndent, pretty)}${childSeparator}${ind}${ node.op - }${node.bool ? " bool" : ""}${matching}${grouping}${childSeparator}${serializeNode( + }${node.bool ? " bool" : ""}${matching}${grouping}${fill}${childSeparator}${serializeNode( maybeParenthesizeBinopChild(node.op, node.rhs), childIndent, pretty diff --git a/web/ui/mantine-ui/src/promql/serializeAndFormat.test.ts b/web/ui/mantine-ui/src/promql/serializeAndFormat.test.ts index a3734d311f..f9ff039882 100644 --- a/web/ui/mantine-ui/src/promql/serializeAndFormat.test.ts +++ b/web/ui/mantine-ui/src/promql/serializeAndFormat.test.ts @@ -658,6 +658,7 @@ describe("serializeNode and formatNode", () => { labels: [], on: false, include: [], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -677,6 +678,7 @@ describe("serializeNode and formatNode", () => { labels: [], on: true, include: [], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -696,6 +698,7 @@ describe("serializeNode and formatNode", () => { labels: ["label1", "label2"], on: true, include: [], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -715,6 +718,7 @@ describe("serializeNode and formatNode", () => { labels: ["label1", "label2"], on: false, include: [], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -735,6 +739,7 @@ describe("serializeNode and formatNode", () => { labels: [], on: false, include: [], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -755,6 +760,7 @@ describe("serializeNode and formatNode", () => { labels: [], on: false, include: ["__name__"], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -774,6 +780,7 @@ describe("serializeNode and formatNode", () => { labels: ["label1", "label2"], on: true, include: [], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -793,6 +800,7 @@ describe("serializeNode and formatNode", () => { labels: ["label1", "label2"], on: true, include: ["label3"], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -812,6 +820,7 @@ describe("serializeNode and formatNode", () => { labels: ["label1", "label2"], on: true, include: [], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -831,6 +840,7 @@ describe("serializeNode and formatNode", () => { labels: ["label1", "label2"], on: true, include: ["label3"], + fillValues: { lhs: null, rhs: null }, }, bool: false, }, @@ -864,6 +874,7 @@ describe("serializeNode and formatNode", () => { labels: ["label1", "label2"], on: true, include: ["label3"], + fillValues: { lhs: null, rhs: null }, }, bool: true, }, @@ -911,6 +922,7 @@ describe("serializeNode and formatNode", () => { include: ["c", "ü"], labels: ["b", "ö"], on: true, + fillValues: { lhs: null, rhs: null }, }, op: binaryOperatorType.div, rhs: { @@ -948,6 +960,7 @@ describe("serializeNode and formatNode", () => { include: [], labels: ["e", "ö"], on: false, + fillValues: { lhs: null, rhs: null }, }, op: binaryOperatorType.add, rhs: { diff --git a/web/ui/module/codemirror-promql/src/complete/promql.terms.ts b/web/ui/module/codemirror-promql/src/complete/promql.terms.ts index d356268d74..3670fffff7 100644 --- a/web/ui/module/codemirror-promql/src/complete/promql.terms.ts +++ b/web/ui/module/codemirror-promql/src/complete/promql.terms.ts @@ -39,6 +39,10 @@ export const binOpModifierTerms = [ { label: 'ignoring', info: 'Ignore specified labels for matching', type: 'keyword' }, { label: 'group_left', info: 'Allow many-to-one matching', type: 'keyword' }, { label: 'group_right', info: 'Allow one-to-many matching', type: 'keyword' }, + { label: 'bool', info: 'Return boolean result (0 or 1) instead of filtering', type: 'keyword' }, + { label: 'fill', info: 'Fill in missing series on both sides', type: 'keyword' }, + { label: 'fill_left', info: 'Fill in missing series on the left side', type: 'keyword' }, + { label: 'fill_right', info: 'Fill in missing series on the right side', type: 'keyword' }, ]; export const atModifierTerms = [ diff --git a/web/ui/module/codemirror-promql/src/parser/vector.test.ts b/web/ui/module/codemirror-promql/src/parser/vector.test.ts index f628206538..c6eeb930ab 100644 --- a/web/ui/module/codemirror-promql/src/parser/vector.test.ts +++ b/web/ui/module/codemirror-promql/src/parser/vector.test.ts @@ -15,29 +15,31 @@ import { buildVectorMatching } from './vector'; import { createEditorState } from '../test/utils-test'; import { BinaryExpr } from '@prometheus-io/lezer-promql'; import { syntaxTree } from '@codemirror/language'; -import { VectorMatchCardinality } from '../types'; +import { VectorMatchCardinality, VectorMatching } from '../types'; + +const noFill = { fill: { lhs: null, rhs: null } }; describe('buildVectorMatching test', () => { - const testCases = [ + const testCases: { binaryExpr: string; expectedVectorMatching: VectorMatching }[] = [ { binaryExpr: 'foo * bar', - expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] }, + expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [], ...noFill }, }, { binaryExpr: 'foo * sum', - expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] }, + expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [], ...noFill }, }, { binaryExpr: 'foo == 1', - expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] }, + expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [], ...noFill }, }, { binaryExpr: 'foo == bool 1', - expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] }, + expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [], ...noFill }, }, { binaryExpr: '2.5 / bar', - expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] }, + expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [], ...noFill }, }, { binaryExpr: 'foo and bar', @@ -46,6 +48,7 @@ describe('buildVectorMatching test', () => { matchingLabels: [], on: false, include: [], + ...noFill, }, }, { @@ -55,6 +58,7 @@ describe('buildVectorMatching test', () => { matchingLabels: [], on: false, include: [], + ...noFill, }, }, { @@ -64,6 +68,7 @@ describe('buildVectorMatching test', () => { matchingLabels: [], on: false, include: [], + ...noFill, }, }, { @@ -75,6 +80,7 @@ describe('buildVectorMatching test', () => { matchingLabels: [], on: false, include: [], + ...noFill, }, }, { @@ -86,6 +92,7 @@ describe('buildVectorMatching test', () => { matchingLabels: [], on: false, include: [], + ...noFill, }, }, { @@ -95,6 +102,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: true, include: [], + ...noFill, }, }, { @@ -104,6 +112,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: true, include: [], + ...noFill, }, }, { @@ -113,6 +122,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: true, include: [], + ...noFill, }, }, { @@ -122,6 +132,7 @@ describe('buildVectorMatching test', () => { matchingLabels: [], on: true, include: [], + ...noFill, }, }, { @@ -131,6 +142,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: false, include: [], + ...noFill, }, }, { @@ -140,6 +152,7 @@ describe('buildVectorMatching test', () => { matchingLabels: [], on: false, include: [], + ...noFill, }, }, { @@ -149,6 +162,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['bar'], on: true, include: [], + ...noFill, }, }, { @@ -158,6 +172,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: true, include: ['bar'], + ...noFill, }, }, { @@ -167,6 +182,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: false, include: ['blub'], + ...noFill, }, }, { @@ -176,6 +192,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: false, include: ['bar'], + ...noFill, }, }, { @@ -185,6 +202,7 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: true, include: ['bar', 'foo'], + ...noFill, }, }, { @@ -194,6 +212,57 @@ describe('buildVectorMatching test', () => { matchingLabels: ['test', 'blub'], on: false, include: ['bar', 'foo'], + ...noFill, + }, + }, + { + binaryExpr: 'foo + fill(23) bar', + expectedVectorMatching: { + card: VectorMatchCardinality.CardOneToOne, + matchingLabels: [], + on: false, + include: [], + fill: { lhs: 23, rhs: 23 }, + }, + }, + { + binaryExpr: 'foo + fill_left(23) bar', + expectedVectorMatching: { + card: VectorMatchCardinality.CardOneToOne, + matchingLabels: [], + on: false, + include: [], + fill: { lhs: 23, rhs: null }, + }, + }, + { + binaryExpr: 'foo + fill_right(23) bar', + expectedVectorMatching: { + card: VectorMatchCardinality.CardOneToOne, + matchingLabels: [], + on: false, + include: [], + fill: { lhs: null, rhs: 23 }, + }, + }, + { + binaryExpr: 'foo + fill_left(23) fill_right(42) bar', + expectedVectorMatching: { + card: VectorMatchCardinality.CardOneToOne, + matchingLabels: [], + on: false, + include: [], + fill: { lhs: 23, rhs: 42 }, + }, + }, + { + binaryExpr: 'foo + fill_right(23) fill_left(42) bar', + expectedVectorMatching: { + card: VectorMatchCardinality.CardOneToOne, + matchingLabels: [], + on: false, + include: [], + fill: { lhs: 42, rhs: 23 }, }, }, ]; @@ -203,7 +272,7 @@ describe('buildVectorMatching test', () => { const node = syntaxTree(state).topNode.getChild(BinaryExpr); expect(node).toBeTruthy(); if (node) { - expect(value.expectedVectorMatching).toEqual(buildVectorMatching(state, node)); + expect(buildVectorMatching(state, node)).toEqual(value.expectedVectorMatching); } }); }); diff --git a/web/ui/module/codemirror-promql/src/parser/vector.ts b/web/ui/module/codemirror-promql/src/parser/vector.ts index c47ca1fb76..9fc31bf5c6 100644 --- a/web/ui/module/codemirror-promql/src/parser/vector.ts +++ b/web/ui/module/codemirror-promql/src/parser/vector.ts @@ -24,6 +24,11 @@ import { On, Or, Unless, + NumberDurationLiteral, + FillModifier, + FillClause, + FillLeftClause, + FillRightClause, } from '@prometheus-io/lezer-promql'; import { VectorMatchCardinality, VectorMatching } from '../types'; import { containsAtLeastOneChild } from './path-finder'; @@ -37,6 +42,10 @@ export function buildVectorMatching(state: EditorState, binaryNode: SyntaxNode): matchingLabels: [], on: false, include: [], + fill: { + lhs: null, + rhs: null, + }, }; const modifierClause = binaryNode.getChild(MatchingModifierClause); if (modifierClause) { @@ -60,6 +69,32 @@ export function buildVectorMatching(state: EditorState, binaryNode: SyntaxNode): } } + const fillModifier = binaryNode.getChild(FillModifier); + if (fillModifier) { + const fill = fillModifier.getChild(FillClause); + const fillLeft = fillModifier.getChild(FillLeftClause); + const fillRight = fillModifier.getChild(FillRightClause); + + const getFillValue = (node: SyntaxNode) => { + const valueNode = node.getChild(NumberDurationLiteral); + return valueNode ? parseFloat(state.sliceDoc(valueNode.from, valueNode.to)) : null; + }; + + if (fill) { + const value = getFillValue(fill); + result.fill.lhs = value; + result.fill.rhs = value; + } + + if (fillLeft) { + result.fill.lhs = getFillValue(fillLeft); + } + + if (fillRight) { + result.fill.rhs = getFillValue(fillRight); + } + } + const isSetOperator = containsAtLeastOneChild(binaryNode, And, Or, Unless); if (isSetOperator && result.card === VectorMatchCardinality.CardOneToOne) { result.card = VectorMatchCardinality.CardManyToMany; diff --git a/web/ui/module/codemirror-promql/src/types/vector.ts b/web/ui/module/codemirror-promql/src/types/vector.ts index 4e7a4f4c45..709b0b76d6 100644 --- a/web/ui/module/codemirror-promql/src/types/vector.ts +++ b/web/ui/module/codemirror-promql/src/types/vector.ts @@ -18,6 +18,11 @@ export enum VectorMatchCardinality { CardManyToMany = 'many-to-many', } +export interface FillValues { + lhs: number | null; + rhs: number | null; +} + export interface VectorMatching { // The cardinality of the two Vectors. card: VectorMatchCardinality; @@ -30,4 +35,6 @@ export interface VectorMatching { // Include contains additional labels that should be included in // the result from the side with the lower cardinality. include: string[]; + // Fill contains optional fill values for missing elements. + fill: FillValues; } diff --git a/web/ui/module/lezer-promql/src/promql.grammar b/web/ui/module/lezer-promql/src/promql.grammar index 5fe8d4d025..9308ad01be 100644 --- a/web/ui/module/lezer-promql/src/promql.grammar +++ b/web/ui/module/lezer-promql/src/promql.grammar @@ -101,11 +101,30 @@ MatchingModifierClause { ((GroupLeft | GroupRight) (!group GroupingLabels)?)? } +FillClause { + Fill "(" NumberDurationLiteral ")" +} + +FillLeftClause { + FillLeft "(" NumberDurationLiteral ")" +} + +FillRightClause { + FillRight "(" NumberDurationLiteral ")" +} + +FillModifier { + (FillClause | FillLeftClause | FillRightClause) | + (FillLeftClause FillRightClause) | + (FillRightClause FillLeftClause) +} + BoolModifier { Bool } binModifiers { BoolModifier? MatchingModifierClause? + FillModifier? } GroupingLabels { @@ -366,7 +385,10 @@ NumberDurationLiteralInDurationContext { Start, End, Smoothed, - Anchored + Anchored, + Fill, + FillLeft, + FillRight } @external propSource promQLHighLight from "./highlight" diff --git a/web/ui/module/lezer-promql/src/tokens.js b/web/ui/module/lezer-promql/src/tokens.js index 523c306ae9..6fd681f1f8 100644 --- a/web/ui/module/lezer-promql/src/tokens.js +++ b/web/ui/module/lezer-promql/src/tokens.js @@ -12,82 +12,88 @@ // limitations under the License. import { - And, - Avg, - Atan2, - Bool, - Bottomk, - By, - Count, - CountValues, - End, - Group, - GroupLeft, - GroupRight, - Ignoring, - inf, - Max, - Min, - nan, - Offset, - On, - Or, - Quantile, - LimitK, - LimitRatio, - Start, - Stddev, - Stdvar, - Sum, - Topk, - Unless, - Without, - Smoothed, - Anchored, -} from './parser.terms.js'; + And, + Avg, + Atan2, + Bool, + Bottomk, + By, + Count, + CountValues, + End, + Group, + GroupLeft, + GroupRight, + Ignoring, + inf, + Max, + Min, + nan, + Offset, + On, + Or, + Quantile, + LimitK, + LimitRatio, + Start, + Stddev, + Stdvar, + Sum, + Topk, + Unless, + Without, + Smoothed, + Anchored, + Fill, + FillLeft, + FillRight, +} from "./parser.terms.js"; const keywordTokens = { - inf: inf, - nan: nan, - bool: Bool, - ignoring: Ignoring, - on: On, - group_left: GroupLeft, - group_right: GroupRight, - offset: Offset, + inf: inf, + nan: nan, + bool: Bool, + ignoring: Ignoring, + on: On, + group_left: GroupLeft, + group_right: GroupRight, + offset: Offset, }; export const specializeIdentifier = (value, stack) => { - return keywordTokens[value.toLowerCase()] || -1; + return keywordTokens[value.toLowerCase()] || -1; }; const contextualKeywordTokens = { - avg: Avg, - atan2: Atan2, - bottomk: Bottomk, - count: Count, - count_values: CountValues, - group: Group, - max: Max, - min: Min, - quantile: Quantile, - limitk: LimitK, - limit_ratio: LimitRatio, - stddev: Stddev, - stdvar: Stdvar, - sum: Sum, - topk: Topk, - by: By, - without: Without, - and: And, - or: Or, - unless: Unless, - start: Start, - end: End, - smoothed: Smoothed, - anchored: Anchored, + avg: Avg, + atan2: Atan2, + bottomk: Bottomk, + count: Count, + count_values: CountValues, + group: Group, + max: Max, + min: Min, + quantile: Quantile, + limitk: LimitK, + limit_ratio: LimitRatio, + stddev: Stddev, + stdvar: Stdvar, + sum: Sum, + topk: Topk, + by: By, + without: Without, + and: And, + or: Or, + unless: Unless, + start: Start, + end: End, + smoothed: Smoothed, + anchored: Anchored, + fill: Fill, + fill_left: FillLeft, + fill_right: FillRight, }; export const extendIdentifier = (value, stack) => { - return contextualKeywordTokens[value.toLowerCase()] || -1; + return contextualKeywordTokens[value.toLowerCase()] || -1; };