From 2f144dd3adad308950b84ca227dd770b0c51f286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= <gyorgy.krajcsovits@grafana.com> Date: Wed, 29 Jan 2025 11:30:47 +0100 Subject: [PATCH] feat(promql): offset from static time expression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related to #12318 . Allow using a PromQL expression for setting the offset, provided that: the expression evaluates to a scalar the expression does not contain vector selector (no TSDB access) the expression does not call the info() function (no TSDB access) the time() function is only called on the top level of the expression, not inside a subquery We'll call such expression a time expression. During parsing we no longer set OriginalOffset field in sub-queries and vector selectors, instead we set a new OriginalOffsetExpr field to the time expression, even if the expression is a literal number. Before evaluating the overall PromQL expression, the engine shall evaluate the time expressions and set the OriginalOffset field in vector selectors and subqueries to the calculated value. This makes the change fairly non intrusive. Later we can change the code to start using the expression more directly. Note: this prohibits using time() function inside a sub-query as the evaluation time is not constant inside a sub-query. Signed-off-by: György Krajcsovits <gyorgy.krajcsovits@grafana.com> --- promql/engine.go | 210 +++++ promql/engine_test.go | 14 +- promql/parser/ast.go | 8 +- promql/parser/functions.go | 26 +- promql/parser/generated_parser.y | 18 +- promql/parser/generated_parser.y.go | 811 +++++++++--------- promql/parser/parse.go | 12 +- promql/parser/parse_test.go | 131 ++- promql/parser/printer.go | 39 +- promql/parser/printer_test.go | 5 + .../testdata/duration_arithmetic.test | 36 + 11 files changed, 827 insertions(+), 483 deletions(-) create mode 100644 promql/promqltest/testdata/duration_arithmetic.test diff --git a/promql/engine.go b/promql/engine.go index 44985e50f9..75a0e7dcaf 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -100,6 +100,9 @@ type ( // ErrStorage is returned if an error was encountered in the storage layer // during query handling. ErrStorage struct{ Err error } + // ErrTimeExprNotAFloat is returned if a time expression evaluates to something + // other than a single float value. + ErrTimeExprNotAFloat string ) func (e ErrQueryTimeout) Error() string { @@ -118,6 +121,20 @@ func (e ErrStorage) Error() string { return e.Err.Error() } +func (e ErrTimeExprNotAFloat) Error() string { + return fmt.Sprintf("time expression evaluates to %s not one float", string(e)) +} + +var ( + // ErrTimeExprUsesStorage is returned if a time expression + // (timestamp/duration) calculation includes vector/range selector. + ErrTimeExprUsesStorage = errors.New("time expression must not use storage") + // ErrTimeExprDependsOnEvalTime is returned if a time expression + // depends on the evaluation time, which is only allowed for the top level + // time expressions. + ErrTimeExprDependsOnEvalTime = errors.New("inner time expression must not depend on the evaluation time") +) + // QueryEngine defines the interface for the *promql.Engine, so it can be replaced, wrapped or mocked. type QueryEngine interface { NewInstantQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, ts time.Time) (Query, error) @@ -486,6 +503,11 @@ func (ng *Engine) NewInstantQuery(ctx context.Context, q storage.Queryable, opts if err != nil { return nil, err } + + if err := ng.PreprocessTimeExpr(expr, ts, ts, 0, opts); err != nil { + return nil, err + } + if err := ng.validateOpts(expr); err != nil { return nil, err } @@ -507,6 +529,11 @@ func (ng *Engine) NewRangeQuery(ctx context.Context, q storage.Queryable, opts Q if err != nil { return nil, err } + + if err := ng.PreprocessTimeExpr(expr, start, end, interval, opts); err != nil { + return nil, err + } + if err := ng.validateOpts(expr); err != nil { return nil, err } @@ -518,6 +545,117 @@ func (ng *Engine) NewRangeQuery(ctx context.Context, q storage.Queryable, opts Q return qry, nil } +type timeExprVisitor struct { + err *error + ev *evaluator + inSubquery bool +} + +func (tev timeExprVisitor) Visit(node parser.Node, path []parser.Node) (parser.Visitor, error) { + checkTimeExpr := func(expr parser.Expr) (float64, error) { + if expr == nil { + return 0, nil + } + + hasStorageDependency, hasEvalTimeDependency := inspectTimeExpr(expr) + if hasStorageDependency { + return 0, ErrTimeExprUsesStorage + } + if tev.inSubquery && hasEvalTimeDependency { + return 0, ErrTimeExprDependsOnEvalTime + } + if nl, ok := expr.(*parser.NumberLiteral); ok { + return nl.Val, nil + } + val, err := tev.ev.timeValueOf(expr) + if err != nil { + return 0, err + } + // Return the precalculated value. + return val, nil + } + + switch e := node.(type) { + case *parser.VectorSelector: + v, err := checkTimeExpr(e.OriginalOffsetExpr) + if err != nil { + *tev.err = err + return tev, err + } + e.OriginalOffset = secondsValueToDuration(v) + return tev, nil + case *parser.SubqueryExpr: + v, err := checkTimeExpr(e.OriginalOffsetExpr) + if err != nil { + *tev.err = err + return tev, err + } + e.OriginalOffset = secondsValueToDuration(v) + return timeExprVisitor{err: tev.err, inSubquery: true}, nil + default: + return tev, nil + } +} + +func inspectTimeExpr(e parser.Expr) (bool, bool) { + var hasStorageDependency, hasEvalTimeDependency bool + parser.Inspect(e, func(node parser.Node, _ []parser.Node) error { + switch n := node.(type) { + case *parser.Call: + if n.Func.EvalTimeDependent { + hasEvalTimeDependency = true + } + if n.Func.StorageDependent { + hasStorageDependency = true + } + case *parser.VectorSelector: + hasStorageDependency = true + } + return nil + }) + return hasStorageDependency, hasEvalTimeDependency +} + +// PreprocessTimeExpr checks the time expressions don't try to load data from +// storage. If the time expression is eval time independent, it will calculate +// its value and replace with a number literal to avoid re-calculations later. +func (ng *Engine) PreprocessTimeExpr(e parser.Expr, start, end time.Time, interval time.Duration, opts QueryOpts) error { + if opts == nil { + opts = NewPrometheusQueryOpts(false, 0) + } + + lookbackDelta := opts.LookbackDelta() + if lookbackDelta <= 0 { + lookbackDelta = ng.lookbackDelta + } + + // Make an evaulator on the heap for the time expressions. + // We only allow time() function on the top level, so using + // "end" timestamp as evaluation time. + ev := evaluator{ + startTimestamp: timeMilliseconds(end), + endTimestamp: timeMilliseconds(end), + interval: 1, + maxSamples: ng.maxSamplesPerQuery, + logger: ng.logger, + lookbackDelta: lookbackDelta, + samplesStats: nil, + noStepSubqueryIntervalFn: ng.noStepSubqueryIntervalFn, + enableDelayedNameRemoval: ng.enableDelayedNameRemoval, + querier: nil, // Fail if we do try to use querier. + } + + var err error + tev := timeExprVisitor{ + err: &err, + ev: &ev, + } + + parser.Walk(tev, e, nil) //nolint:errcheck + + return *tev.err +} + func (ng *Engine) newQuery(q storage.Queryable, qs string, opts QueryOpts, start, end time.Time, interval time.Duration) (*parser.Expr, *query) { if opts == nil { opts = NewPrometheusQueryOpts(false, 0) @@ -3844,3 +3982,75 @@ func (ev *evaluator) gatherVector(ts int64, input Matrix, output Vector, bufHelp return output, bufHelpers } + +// timeValueOf calculates the scalar time value of an expression in float64. +func (ev *evaluator) timeValueOf(e parser.Expr) (float64, error) { + if e == nil { + return 0, nil + } + + if ev.querier != nil { + panic("evaulator does not disallow querier for time expressions") + } + + // Shortcut for number literals. + if nl, ok := e.(*parser.NumberLiteral); ok { + return nl.Val, nil + } + + // We can only use scalars as timestamp or duration. + if e.Type() != parser.ValueTypeScalar { + panic("parser should have discarded non scalar time expression") + } + + // TODO(krajorama): would we ever get annotations here? + res, _, err := ev.Eval(context.Background(), e) + if err != nil { + return 0, err + } + + var value float64 + + switch v := res.(type) { + case Scalar: + value = v.V + case String: + return 0, ErrTimeExprNotAFloat("string") + case Vector: + if len(v) > 0 { + return 0, ErrTimeExprNotAFloat("vector with multiple samples") + } + if len(v) == 0 { + return 0, ErrTimeExprNotAFloat("vector with no samples") + } + if v[0].H != nil { + return 0, ErrTimeExprNotAFloat("vector with a histogram element") + } + return v[0].F, nil + case Matrix: + if len(v) > 1 { + return 0, ErrTimeExprNotAFloat("matrix with more than one series") + } + if len(v) == 0 { + return 0, ErrTimeExprNotAFloat("matrix with no series") + } + s := v[0] + if len(s.Histograms) > 0 { + return 0, ErrTimeExprNotAFloat("matrix with histograms") + } + if len(s.Floats) > 1 { + return 0, ErrTimeExprNotAFloat("matrix with more than one element") + } + if len(s.Floats) == 0 { + return 0, ErrTimeExprNotAFloat("matrix with no element") + } + return s.Floats[0].F, nil + default: + return 0, ErrTimeExprNotAFloat("unknown type") + } + return value, nil +} + +func secondsValueToDuration(v float64) time.Duration { + return time.Duration(v*1000.0) * time.Millisecond +} diff --git a/promql/engine_test.go b/promql/engine_test.go index 9ba93abc78..7cf0474246 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -2739,8 +2739,8 @@ func TestPreprocessAndWrapWithStepInvariantExpr(t *testing.T) { Start: 0, End: 27, }, - Timestamp: makeInt64Pointer(123000), - OriginalOffset: 1 * time.Minute, + Timestamp: makeInt64Pointer(123000), + OriginalOffsetExpr: &parser.NumberLiteral{Val: float64(1 * time.Minute / time.Second)}, }, }, Range: 10 * time.Minute, @@ -2762,11 +2762,11 @@ func TestPreprocessAndWrapWithStepInvariantExpr(t *testing.T) { End: 11, }, }, - Timestamp: makeInt64Pointer(123000), - OriginalOffset: 1 * time.Minute, - Range: 10 * time.Minute, - Step: 5 * time.Second, - EndPos: 35, + Timestamp: makeInt64Pointer(123000), + OriginalOffsetExpr: &parser.NumberLiteral{Val: float64(1 * time.Minute / time.Second)}, + Range: 10 * time.Minute, + Step: 5 * time.Second, + EndPos: 35, }, }, }, diff --git a/promql/parser/ast.go b/promql/parser/ast.go index 132ef3f0d2..4b34b0a82d 100644 --- a/promql/parser/ast.go +++ b/promql/parser/ast.go @@ -133,8 +133,10 @@ type MatrixSelector struct { type SubqueryExpr struct { Expr Expr Range time.Duration + // OriginalOffsetExpr is the parsed expression for OriginalOffset + OriginalOffsetExpr Expr // OriginalOffset is the actual offset that was set in the query. - // This never changes. + // Precalculated from the OriginalOffsetExpr and then never changes. OriginalOffset time.Duration // Offset is the offset used during the query execution // which is calculated using the original offset, at modifier time, @@ -192,8 +194,10 @@ func (e *StepInvariantExpr) PositionRange() posrange.PositionRange { // VectorSelector represents a Vector selection. type VectorSelector struct { Name string + // OriginalOffsetExpr is the parsed expression for OriginalOffset + OriginalOffsetExpr Expr // OriginalOffset is the actual offset that was set in the query. - // This never changes. + // Precalculated from the OriginalOffsetExpr and then never changes. OriginalOffset time.Duration // Offset is the offset used during the query execution // which is calculated using the original offset, at modifier time, diff --git a/promql/parser/functions.go b/promql/parser/functions.go index aa65aca275..7de3cf5da4 100644 --- a/promql/parser/functions.go +++ b/promql/parser/functions.go @@ -21,6 +21,14 @@ type Function struct { Variadic int ReturnType ValueType Experimental bool + + // EvalTimeDependent means that the output of the function depends on what + // the current evaluation timestamp is. For example time(). + EvalTimeDependent bool + + // StorageDependent means that the out of the function depends on the + // content of TSDB at the time. For example info(). + StorageDependent bool } // EnableExperimentalFunctions controls whether experimentalFunctions are enabled. @@ -225,11 +233,12 @@ var Functions = map[string]*Function{ ReturnType: ValueTypeVector, }, "info": { - Name: "info", - ArgTypes: []ValueType{ValueTypeVector, ValueTypeVector}, - ReturnType: ValueTypeVector, - Experimental: true, - Variadic: 1, + Name: "info", + ArgTypes: []ValueType{ValueTypeVector, ValueTypeVector}, + ReturnType: ValueTypeVector, + Experimental: true, + Variadic: 1, + StorageDependent: true, }, "irate": { Name: "irate", @@ -411,9 +420,10 @@ var Functions = map[string]*Function{ ReturnType: ValueTypeVector, }, "time": { - Name: "time", - ArgTypes: []ValueType{}, - ReturnType: ValueTypeScalar, + Name: "time", + ArgTypes: []ValueType{}, + ReturnType: ValueTypeScalar, + EvalTimeDependent: true, }, "timestamp": { Name: "timestamp", diff --git a/promql/parser/generated_parser.y b/promql/parser/generated_parser.y index cdb4532d3b..008003ea8e 100644 --- a/promql/parser/generated_parser.y +++ b/promql/parser/generated_parser.y @@ -436,19 +436,27 @@ paren_expr : LEFT_PAREN expr RIGHT_PAREN offset_expr: expr OFFSET number_duration_literal { numLit, _ := $3.(*NumberLiteral) - dur := time.Duration(numLit.Val * 1000) * time.Millisecond + dur := &NumberLiteral{Val: numLit.Val} yylex.(*parser).addOffset($1, dur) $$ = $1 } | expr OFFSET SUB number_duration_literal { numLit, _ := $4.(*NumberLiteral) - dur := time.Duration(numLit.Val * 1000) * time.Millisecond - yylex.(*parser).addOffset($1, -dur) + dur := &NumberLiteral{Val: numLit.Val * -1.0} + yylex.(*parser).addOffset($1, dur) $$ = $1 } + | expr OFFSET paren_expr + { + dur, _ := $3.(*ParenExpr) + if dur.Type() != ValueTypeScalar { + yylex.(*parser).unexpected("offset", "time expression does not evaluate to a scalar") + } + yylex.(*parser).addOffset($1, dur) + } | expr OFFSET error - { yylex.(*parser).unexpected("offset", "number or duration"); $$ = $1 } + { yylex.(*parser).unexpected("offset", "number or duration or time expression in parentheses"); $$ = $1 } ; /* * @ modifiers. @@ -480,7 +488,7 @@ matrix_selector : expr LEFT_BRACKET number_duration_literal RIGHT_BRACKET vs, ok := $1.(*VectorSelector) if !ok{ errMsg = "ranges only allowed for vector selectors" - } else if vs.OriginalOffset != 0{ + } else if vs.OriginalOffsetExpr != nil { errMsg = "no offset modifiers allowed before range" } else if vs.Timestamp != nil { errMsg = "no @ modifiers allowed before range" diff --git a/promql/parser/generated_parser.y.go b/promql/parser/generated_parser.y.go index 78d5e15245..472357bc82 100644 --- a/promql/parser/generated_parser.y.go +++ b/promql/parser/generated_parser.y.go @@ -251,295 +251,295 @@ var yyExca = [...]int16{ 1, -1, -2, 0, -1, 37, - 1, 141, - 10, 141, - 24, 141, + 1, 142, + 10, 142, + 24, 142, -2, 0, -1, 61, - 2, 184, - 15, 184, - 79, 184, - 85, 184, - -2, 102, - -1, 62, 2, 185, 15, 185, 79, 185, 85, 185, -2, 103, - -1, 63, + -1, 62, 2, 186, 15, 186, 79, 186, 85, 186, - -2, 105, - -1, 64, + -2, 104, + -1, 63, 2, 187, 15, 187, 79, 187, 85, 187, -2, 106, - -1, 65, + -1, 64, 2, 188, 15, 188, 79, 188, 85, 188, -2, 107, - -1, 66, + -1, 65, 2, 189, 15, 189, 79, 189, 85, 189, - -2, 112, - -1, 67, + -2, 108, + -1, 66, 2, 190, 15, 190, 79, 190, 85, 190, - -2, 114, - -1, 68, + -2, 113, + -1, 67, 2, 191, 15, 191, 79, 191, 85, 191, - -2, 116, - -1, 69, + -2, 115, + -1, 68, 2, 192, 15, 192, 79, 192, 85, 192, -2, 117, - -1, 70, + -1, 69, 2, 193, 15, 193, 79, 193, 85, 193, -2, 118, - -1, 71, + -1, 70, 2, 194, 15, 194, 79, 194, 85, 194, -2, 119, - -1, 72, + -1, 71, 2, 195, 15, 195, 79, 195, 85, 195, -2, 120, - -1, 73, + -1, 72, 2, 196, 15, 196, 79, 196, 85, 196, - -2, 124, - -1, 74, + -2, 121, + -1, 73, 2, 197, 15, 197, 79, 197, 85, 197, -2, 125, - -1, 204, - 9, 246, - 12, 246, - 13, 246, - 18, 246, - 19, 246, - 25, 246, - 41, 246, - 47, 246, - 48, 246, - 51, 246, - 57, 246, - 62, 246, - 63, 246, - 64, 246, - 65, 246, - 66, 246, - 67, 246, - 68, 246, - 69, 246, - 70, 246, - 71, 246, - 72, 246, - 73, 246, - 74, 246, - 75, 246, - 79, 246, - 83, 246, - 85, 246, - 88, 246, - 89, 246, - -2, 0, + -1, 74, + 2, 198, + 15, 198, + 79, 198, + 85, 198, + -2, 126, -1, 205, - 9, 246, - 12, 246, - 13, 246, - 18, 246, - 19, 246, - 25, 246, - 41, 246, - 47, 246, - 48, 246, - 51, 246, - 57, 246, - 62, 246, - 63, 246, - 64, 246, - 65, 246, - 66, 246, - 67, 246, - 68, 246, - 69, 246, - 70, 246, - 71, 246, - 72, 246, - 73, 246, - 74, 246, - 75, 246, - 79, 246, - 83, 246, - 85, 246, - 88, 246, - 89, 246, + 9, 247, + 12, 247, + 13, 247, + 18, 247, + 19, 247, + 25, 247, + 41, 247, + 47, 247, + 48, 247, + 51, 247, + 57, 247, + 62, 247, + 63, 247, + 64, 247, + 65, 247, + 66, 247, + 67, 247, + 68, 247, + 69, 247, + 70, 247, + 71, 247, + 72, 247, + 73, 247, + 74, 247, + 75, 247, + 79, 247, + 83, 247, + 85, 247, + 88, 247, + 89, 247, + -2, 0, + -1, 206, + 9, 247, + 12, 247, + 13, 247, + 18, 247, + 19, 247, + 25, 247, + 41, 247, + 47, 247, + 48, 247, + 51, 247, + 57, 247, + 62, 247, + 63, 247, + 64, 247, + 65, 247, + 66, 247, + 67, 247, + 68, 247, + 69, 247, + 70, 247, + 71, 247, + 72, 247, + 73, 247, + 74, 247, + 75, 247, + 79, 247, + 83, 247, + 85, 247, + 88, 247, + 89, 247, -2, 0, } const yyPrivate = 57344 -const yyLast = 803 +const yyLast = 804 var yyAct = [...]int16{ - 154, 338, 336, 157, 343, 230, 39, 196, 280, 44, - 295, 294, 84, 120, 82, 233, 180, 109, 108, 350, - 351, 352, 353, 110, 111, 243, 202, 158, 203, 135, - 112, 249, 361, 6, 333, 329, 113, 332, 232, 204, - 205, 308, 271, 60, 130, 270, 297, 268, 162, 315, - 156, 360, 153, 306, 359, 344, 200, 162, 161, 55, - 245, 246, 222, 115, 247, 116, 107, 161, 269, 54, - 267, 114, 260, 306, 182, 234, 236, 238, 239, 240, - 248, 250, 253, 254, 255, 256, 257, 261, 262, 163, - 122, 235, 237, 241, 242, 244, 251, 252, 192, 328, - 111, 258, 259, 117, 190, 164, 112, 152, 103, 55, - 106, 337, 77, 113, 184, 151, 35, 165, 327, 54, - 175, 191, 169, 172, 183, 185, 167, 189, 168, 2, - 3, 4, 5, 107, 198, 105, 159, 160, 201, 186, - 188, 7, 326, 206, 207, 208, 209, 210, 211, 212, - 213, 214, 215, 216, 217, 218, 219, 220, 199, 194, - 89, 91, 221, 162, 264, 325, 197, 223, 224, 171, - 200, 100, 101, 161, 162, 103, 104, 106, 90, 263, - 233, 324, 170, 162, 161, 323, 362, 322, 321, 274, - 243, 122, 266, 161, 131, 163, 249, 272, 123, 320, - 229, 319, 105, 232, 275, 318, 163, 317, 121, 85, - 316, 164, 163, 292, 293, 163, 265, 296, 129, 83, - 276, 86, 164, 273, 10, 245, 246, 187, 164, 247, - 88, 164, 86, 50, 79, 36, 298, 260, 1, 78, - 234, 236, 238, 239, 240, 248, 250, 253, 254, 255, - 256, 257, 261, 262, 123, 49, 235, 237, 241, 242, - 244, 251, 252, 181, 121, 182, 258, 259, 128, 48, - 127, 304, 119, 305, 307, 59, 309, 86, 9, 9, - 47, 46, 134, 310, 311, 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, - 45, 43, 132, 173, 179, 184, 166, 85, 330, 178, - 331, 42, 133, 55, 41, 183, 185, 83, 339, 340, - 341, 335, 177, 54, 342, 81, 346, 345, 348, 347, - 86, 303, 40, 314, 354, 355, 302, 55, 51, 356, - 53, 77, 300, 56, 195, 358, 22, 54, 313, 55, - 174, 301, 227, 57, 8, 312, 226, 357, 37, 54, - 363, 299, 126, 277, 87, 193, 228, 125, 80, 75, - 349, 225, 155, 58, 231, 18, 19, 52, 118, 20, - 124, 0, 0, 0, 0, 76, 0, 0, 0, 0, + 155, 339, 337, 158, 344, 231, 39, 197, 281, 44, + 296, 295, 84, 120, 82, 234, 181, 109, 108, 46, + 351, 352, 353, 354, 111, 244, 110, 159, 205, 206, + 112, 250, 203, 6, 204, 330, 135, 362, 233, 113, + 334, 333, 309, 272, 60, 154, 271, 269, 298, 130, + 157, 307, 55, 316, 201, 329, 361, 163, 56, 360, + 246, 247, 54, 115, 248, 116, 107, 162, 307, 270, + 268, 114, 261, 223, 328, 235, 237, 239, 240, 241, + 249, 251, 254, 255, 256, 257, 258, 262, 263, 164, + 122, 236, 238, 242, 243, 245, 252, 253, 265, 315, + 152, 259, 260, 111, 117, 165, 338, 304, 103, 112, + 106, 172, 303, 264, 314, 151, 113, 166, 193, 191, + 176, 313, 170, 173, 171, 153, 168, 302, 169, 2, + 3, 4, 5, 107, 199, 105, 160, 161, 202, 187, + 189, 192, 190, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 200, 345, + 89, 91, 222, 77, 163, 35, 183, 275, 224, 225, + 7, 100, 101, 163, 162, 103, 104, 106, 90, 273, + 228, 234, 276, 162, 227, 363, 327, 182, 326, 183, + 123, 244, 122, 267, 164, 131, 164, 250, 277, 226, + 121, 230, 105, 325, 233, 164, 185, 324, 266, 163, + 165, 323, 165, 86, 293, 294, 184, 186, 297, 162, + 322, 165, 55, 10, 274, 321, 246, 247, 320, 185, + 248, 319, 54, 79, 318, 317, 129, 299, 261, 184, + 186, 235, 237, 239, 240, 241, 249, 251, 254, 255, + 256, 257, 258, 262, 263, 85, 88, 236, 238, 242, + 243, 245, 252, 253, 301, 83, 36, 259, 260, 1, + 50, 55, 305, 188, 306, 308, 78, 310, 86, 49, + 128, 54, 127, 300, 311, 312, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 195, 8, 48, 47, 163, 37, 167, 198, 331, + 134, 332, 201, 180, 55, 162, 123, 45, 179, 340, + 341, 342, 336, 43, 54, 343, 121, 347, 346, 349, + 348, 178, 132, 174, 119, 355, 356, 164, 55, 86, + 357, 53, 77, 42, 56, 85, 359, 22, 54, 133, + 41, 175, 40, 165, 57, 83, 59, 126, 51, 9, + 9, 364, 125, 81, 196, 358, 278, 87, 86, 194, + 75, 229, 80, 350, 156, 124, 18, 19, 58, 232, + 20, 52, 118, 0, 0, 0, 76, 0, 0, 0, + 0, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 0, 0, 0, 13, 0, + 0, 0, 24, 0, 30, 0, 0, 31, 32, 55, + 38, 107, 53, 77, 0, 56, 280, 0, 22, 54, + 0, 0, 0, 279, 0, 57, 0, 283, 284, 282, + 289, 291, 288, 290, 285, 286, 287, 292, 0, 91, + 0, 75, 0, 0, 0, 0, 0, 18, 19, 100, + 101, 20, 0, 103, 0, 106, 90, 76, 0, 0, + 0, 0, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 0, 0, 0, 13, + 105, 0, 0, 24, 0, 30, 0, 55, 31, 32, + 53, 77, 0, 56, 335, 0, 22, 54, 0, 0, + 0, 0, 0, 57, 0, 283, 284, 282, 289, 291, + 288, 290, 285, 286, 287, 292, 0, 0, 0, 75, + 0, 0, 0, 0, 0, 18, 19, 0, 0, 20, + 0, 0, 0, 17, 77, 76, 0, 0, 0, 22, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 0, 0, 0, 13, 0, 0, - 0, 24, 0, 30, 0, 0, 31, 32, 55, 38, - 107, 53, 77, 0, 56, 279, 0, 22, 54, 0, - 0, 0, 278, 0, 57, 0, 282, 283, 281, 288, - 290, 287, 289, 284, 285, 286, 291, 0, 91, 0, - 75, 0, 0, 0, 0, 0, 18, 19, 100, 101, - 20, 0, 103, 0, 106, 90, 76, 0, 0, 0, - 0, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 0, 0, 0, 13, 105, - 0, 0, 24, 0, 30, 0, 55, 31, 32, 53, - 77, 0, 56, 334, 0, 22, 54, 0, 0, 0, - 0, 0, 57, 0, 282, 283, 281, 288, 290, 287, - 289, 284, 285, 286, 291, 0, 0, 0, 75, 0, - 0, 0, 0, 0, 18, 19, 0, 0, 20, 0, - 0, 0, 17, 77, 76, 0, 0, 0, 22, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 0, 0, 0, 13, 0, 0, 0, - 24, 0, 30, 0, 0, 31, 32, 18, 19, 0, - 0, 20, 0, 0, 0, 17, 35, 0, 0, 0, - 0, 22, 11, 12, 14, 15, 16, 21, 23, 25, - 26, 27, 28, 29, 33, 34, 0, 0, 0, 13, - 0, 0, 0, 24, 0, 30, 0, 0, 31, 32, - 18, 19, 0, 0, 20, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 11, 12, 14, 15, 16, - 21, 23, 25, 26, 27, 28, 29, 33, 34, 107, - 0, 0, 13, 0, 0, 0, 24, 176, 30, 0, - 0, 31, 32, 0, 0, 0, 0, 0, 107, 0, - 0, 0, 0, 0, 0, 0, 89, 91, 92, 0, + 0, 24, 0, 30, 0, 0, 31, 32, 18, 19, + 0, 0, 20, 0, 0, 0, 17, 35, 0, 0, + 0, 0, 22, 11, 12, 14, 15, 16, 21, 23, + 25, 26, 27, 28, 29, 33, 34, 0, 0, 0, + 13, 0, 0, 0, 24, 0, 30, 0, 0, 31, + 32, 18, 19, 0, 0, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 12, 14, 15, + 16, 21, 23, 25, 26, 27, 28, 29, 33, 34, + 107, 0, 0, 13, 0, 0, 0, 24, 177, 30, + 0, 0, 31, 32, 0, 0, 0, 0, 0, 107, + 0, 0, 0, 0, 0, 0, 0, 89, 91, 92, + 0, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 0, 103, 104, 106, 90, 89, 91, 92, 0, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 0, 103, 104, 106, 90, 89, 91, 92, 0, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 0, - 103, 104, 106, 90, 107, 0, 0, 0, 105, 0, + 0, 103, 104, 106, 90, 107, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 107, 0, 0, 0, 105, 0, 0, - 0, 89, 91, 92, 0, 93, 94, 95, 0, 97, - 98, 99, 100, 101, 102, 0, 103, 104, 106, 90, - 89, 91, 92, 0, 93, 94, 0, 0, 97, 98, - 0, 100, 101, 102, 0, 103, 104, 106, 90, 0, - 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 107, 0, 0, 0, 105, 0, + 0, 0, 89, 91, 92, 0, 93, 94, 95, 0, + 97, 98, 99, 100, 101, 102, 0, 103, 104, 106, + 90, 89, 91, 92, 0, 93, 94, 0, 0, 97, + 98, 0, 100, 101, 102, 0, 103, 104, 106, 90, + 0, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 105, + 0, 0, 0, 105, } var yyPact = [...]int16{ - 31, 131, 573, 573, 409, 530, -1000, -1000, -1000, 103, + 31, 160, 574, 574, 410, 531, -1000, -1000, -1000, 152, -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, 305, -1000, 228, -1000, 654, + -1000, -1000, -1000, -1000, -1000, 343, -1000, 254, -1000, 655, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 21, 98, -1000, -1000, 487, -1000, 487, 99, + -1000, -1000, 24, 101, -1000, -1000, 488, -1000, 488, 150, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 252, -1000, -1000, - 360, -1000, -1000, 266, 214, -1000, -1000, 20, -1000, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, 50, 48, 304, 98, -55, - -1000, 167, 167, 328, -1000, 635, 52, -1000, 302, -1000, - -1000, 261, 70, -1000, -1000, 207, -1000, 102, -1000, 96, - 154, 487, -1000, -56, -41, -1000, 487, 487, 487, 487, - 487, 487, 487, 487, 487, 487, 487, 487, 487, 487, - 487, -1000, 100, -1000, -1000, 47, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 39, 39, 350, -1000, -1000, -1000, -1000, - 178, -1000, -1000, 157, -1000, 654, -1000, -1000, 196, -1000, - 45, -1000, -1000, -1000, -1000, -1000, 43, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 16, 171, 163, -1000, -1000, -1000, - 408, 406, 167, 167, 167, 167, 52, 52, 119, 119, - 119, 719, 700, 119, 119, 719, 52, 52, 119, 52, - 406, -1000, 24, -1000, -1000, -1000, 340, -1000, 329, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 314, -1000, -1000, + 355, -1000, -1000, 278, 232, -1000, -1000, 25, -1000, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, 43, 48, 305, 101, -55, + -1000, 109, 109, 329, -1000, 636, 52, -1000, 311, -1000, + -1000, 185, 162, -1000, -1000, 253, -1000, 117, -1000, 116, + 296, 488, -1000, -50, -52, -1000, 488, 488, 488, 488, + 488, 488, 488, 488, 488, 488, 488, 488, 488, 488, + 488, -1000, 213, -1000, -1000, -1000, 58, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 200, 200, 178, -1000, -1000, -1000, + -1000, 179, -1000, -1000, 91, -1000, 655, -1000, -1000, 188, + -1000, 45, -1000, -1000, -1000, -1000, -1000, 44, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 17, 153, 141, -1000, -1000, + -1000, 409, 407, 109, 109, 109, 109, 52, 52, 119, + 119, 119, 720, 701, 119, 119, 720, 52, 52, 119, + 52, 407, -1000, 26, -1000, -1000, -1000, 262, -1000, 105, -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, 487, -1000, -1000, -1000, -1000, -1000, - -1000, 34, 34, 15, 34, 40, 40, 331, 32, -1000, - -1000, 204, 201, 199, 195, 193, 182, 181, 179, 175, - 159, 136, -1000, -1000, -1000, -1000, -1000, -1000, 97, -1000, - -1000, -1000, 13, -1000, 654, -1000, -1000, -1000, 34, -1000, - 11, 8, 486, -1000, -1000, -1000, 54, 174, 174, 174, - 39, 41, 41, 54, 41, 54, -73, -1000, -1000, -1000, - -1000, -1000, 34, 34, -1000, -1000, -1000, 34, -1000, -1000, - -1000, -1000, -1000, -1000, 174, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 30, -1000, 165, - -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 488, -1000, -1000, -1000, -1000, + -1000, -1000, 32, 32, 16, 32, 38, 38, 97, 36, + -1000, -1000, 229, 228, 225, 222, 219, 214, 205, 201, + 197, 182, 180, -1000, -1000, -1000, -1000, -1000, -1000, 53, + -1000, -1000, -1000, 13, -1000, 655, -1000, -1000, -1000, 32, + -1000, 15, 14, 487, -1000, -1000, -1000, 49, 155, 155, + 155, 200, 145, 145, 49, 145, 49, -72, -1000, -1000, + -1000, -1000, -1000, 32, 32, -1000, -1000, -1000, 32, -1000, + -1000, -1000, -1000, -1000, -1000, 155, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 35, -1000, + 164, -1000, -1000, -1000, -1000, } var yyPgo = [...]int16{ - 0, 378, 13, 377, 5, 16, 374, 275, 373, 372, - 12, 370, 224, 354, 368, 14, 366, 10, 11, 365, - 364, 7, 363, 8, 4, 357, 2, 1, 3, 344, - 27, 0, 338, 332, 18, 194, 314, 312, 6, 311, - 303, 17, 302, 43, 301, 9, 300, 282, 281, 280, - 269, 255, 233, 238, 235, + 0, 382, 13, 381, 5, 16, 379, 356, 378, 374, + 12, 373, 223, 302, 372, 14, 371, 10, 11, 369, + 367, 7, 366, 8, 4, 365, 2, 1, 3, 364, + 27, 0, 358, 352, 18, 195, 350, 349, 6, 343, + 333, 17, 332, 44, 323, 9, 317, 310, 19, 304, + 303, 279, 270, 269, 266, } var yyR1 = [...]int8{ @@ -550,24 +550,24 @@ var yyR1 = [...]int8{ 36, 36, 35, 37, 37, 47, 47, 42, 42, 42, 42, 17, 17, 17, 17, 16, 16, 16, 4, 4, 4, 39, 41, 41, 40, 40, 40, 48, 46, 46, - 46, 32, 32, 32, 9, 9, 44, 50, 50, 50, - 50, 50, 50, 51, 52, 52, 52, 43, 43, 43, - 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, - 13, 13, 7, 7, 7, 7, 7, 7, 7, 7, + 46, 46, 32, 32, 32, 9, 9, 44, 50, 50, + 50, 50, 50, 50, 51, 52, 52, 52, 43, 43, + 43, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 2, 13, 13, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, - 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, - 54, 20, 20, 20, 20, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 29, 29, 29, 21, 21, 21, - 21, 22, 22, 22, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 24, 24, 25, 25, 25, - 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, + 12, 14, 14, 14, 15, 15, 15, 15, 15, 15, + 15, 54, 20, 20, 20, 20, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 29, 29, 29, 21, 21, + 21, 21, 22, 22, 22, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 24, 24, 25, 25, + 25, 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, 8, 8, 5, - 5, 5, 5, 45, 45, 28, 28, 30, 30, 31, - 31, 27, 26, 26, 49, 10, 18, 18, + 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, + 5, 5, 5, 5, 45, 45, 28, 28, 30, 30, + 31, 31, 27, 26, 26, 49, 10, 18, 18, } var yyR2 = [...]int8{ @@ -578,24 +578,24 @@ var yyR2 = [...]int8{ 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, 3, 4, - 3, 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, + 3, 3, 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, 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, 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, 2, 2, 1, - 1, 1, 2, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 1, 1, 1, 2, 1, 1, 1, 0, 1, } var yyChk = [...]int16{ @@ -614,68 +614,68 @@ var yyChk = [...]int16{ -2, 12, -10, 2, 20, 7, 2, 4, 2, 4, 24, -35, -42, -37, -47, 78, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -45, 57, 2, -31, -9, 2, -28, -30, 88, - 89, 19, 9, 41, 57, -45, 2, -41, -34, -17, - 15, 2, -17, -40, 22, -38, 22, 20, 7, 2, - -5, 2, 4, 54, 44, 55, -5, 20, -15, 25, - 2, 25, 2, -19, 5, -29, -21, 12, -28, -30, - 16, -38, 82, 84, 80, 81, -38, -38, -38, -38, + -35, -45, 57, -48, 2, -31, -9, 2, -28, -30, + 88, 89, 19, 9, 41, 57, -45, 2, -41, -34, + -17, 15, 2, -17, -40, 22, -38, 22, 20, 7, + 2, -5, 2, 4, 54, 44, 55, -5, 20, -15, + 25, 2, 25, 2, -19, 5, -29, -21, 12, -28, + -30, 16, -38, 82, 84, 80, 81, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, - -38, -45, 15, -28, -28, 21, 6, 2, -16, 22, - -4, -6, 25, 2, 62, 78, 63, 79, 64, 65, - 66, 80, 81, 12, 82, 47, 48, 51, 67, 18, - 68, 83, 84, 69, 70, 71, 72, 73, 88, 89, - 59, 74, 75, 22, 7, 20, -2, 25, 2, 25, - 2, 26, 26, -30, 26, 41, 57, -22, 24, 17, - -23, 30, 28, 29, 35, 36, 37, 33, 31, 34, - 32, 38, -17, -17, -18, -17, -18, 22, -45, 21, - 2, 22, 7, 2, -38, -27, 19, -27, 26, -27, - -21, -21, 24, 17, 2, 17, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 21, 2, 22, - -4, -27, 26, 26, 17, -23, -26, 57, -27, -31, - -31, -31, -28, -24, 14, -24, -26, -24, -26, -11, - 92, 93, 94, 95, -27, -27, -27, -25, -31, 24, - 21, 2, 21, -31, + -38, -38, -45, 15, -28, -28, 21, 6, 2, -16, + 22, -4, -6, 25, 2, 62, 78, 63, 79, 64, + 65, 66, 80, 81, 12, 82, 47, 48, 51, 67, + 18, 68, 83, 84, 69, 70, 71, 72, 73, 88, + 89, 59, 74, 75, 22, 7, 20, -2, 25, 2, + 25, 2, 26, 26, -30, 26, 41, 57, -22, 24, + 17, -23, 30, 28, 29, 35, 36, 37, 33, 31, + 34, 32, 38, -17, -17, -18, -17, -18, 22, -45, + 21, 2, 22, 7, 2, -38, -27, 19, -27, 26, + -27, -21, -21, 24, 17, 2, 17, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 21, 2, + 22, -4, -27, 26, 26, 17, -23, -26, 57, -27, + -31, -31, -31, -28, -24, 14, -24, -26, -24, -26, + -11, 92, 93, 94, 95, -27, -27, -27, -25, -31, + 24, 21, 2, 21, -31, } var yyDef = [...]int16{ - 0, -2, 129, 129, 0, 0, 7, 6, 1, 129, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 2, -2, 3, 4, + 0, -2, 130, 130, 0, 0, 7, 6, 1, 130, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 0, 2, -2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 0, 108, 233, 234, 0, 244, 0, 85, - 86, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, 227, 228, 0, 5, 100, - 0, 128, 131, 0, 135, 139, 245, 140, 144, 43, + 18, 19, 0, 109, 234, 235, 0, 245, 0, 86, + 87, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, 228, 229, 0, 5, 101, + 0, 129, 132, 0, 136, 140, 246, 141, 145, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 0, 0, 0, 0, 22, - 23, 0, 0, 0, 61, 0, 83, 84, 0, 89, - 91, 0, 95, 99, 126, 0, 132, 0, 138, 0, - 143, 0, 42, 47, 48, 44, 0, 0, 0, 0, + 23, 0, 0, 0, 61, 0, 84, 85, 0, 90, + 92, 0, 96, 100, 127, 0, 133, 0, 139, 0, + 144, 0, 42, 47, 48, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 68, 0, 70, 71, 0, 73, 239, 240, 74, - 75, 235, 236, 0, 0, 0, 82, 20, 21, 24, - 0, 54, 25, 0, 63, 65, 67, 87, 0, 92, - 0, 98, 229, 230, 231, 232, 0, 127, 130, 133, - 136, 134, 137, 142, 145, 147, 150, 154, 155, 156, - 0, 26, 0, 0, -2, -2, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 69, 0, 237, 238, 76, 0, 81, 0, 53, - 56, 58, 59, 60, 198, 199, 200, 201, 202, 203, + 0, 68, 0, 70, 71, 72, 0, 74, 240, 241, + 75, 76, 236, 237, 0, 0, 0, 83, 20, 21, + 24, 0, 54, 25, 0, 63, 65, 67, 88, 0, + 93, 0, 99, 230, 231, 232, 233, 0, 128, 131, + 134, 137, 135, 138, 143, 146, 148, 151, 155, 156, + 157, 0, 26, 0, 0, -2, -2, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 69, 0, 238, 239, 77, 0, 82, 0, + 53, 56, 58, 59, 60, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 62, 66, 88, 90, 93, 97, 94, - 96, 0, 0, 0, 0, 0, 0, 0, 0, 160, - 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 45, 46, 49, 247, 50, 72, 0, 78, - 80, 51, 0, 57, 64, 146, 241, 148, 0, 151, - 0, 0, 0, 158, 163, 159, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 77, 79, 52, - 55, 149, 0, 0, 157, 161, 164, 0, 243, 165, - 166, 167, 168, 169, 0, 170, 171, 172, 173, 174, - 180, 181, 182, 183, 152, 153, 242, 0, 178, 0, - 176, 179, 175, 177, + 224, 225, 226, 227, 62, 66, 89, 91, 94, 98, + 95, 97, 0, 0, 0, 0, 0, 0, 0, 0, + 161, 163, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 46, 49, 248, 50, 73, 0, + 79, 81, 51, 0, 57, 64, 147, 242, 149, 0, + 152, 0, 0, 0, 159, 164, 160, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 78, 80, + 52, 55, 150, 0, 0, 158, 162, 165, 0, 244, + 166, 167, 168, 169, 170, 0, 171, 172, 173, 174, + 175, 181, 182, 183, 184, 153, 154, 243, 0, 179, + 0, 177, 180, 176, 178, } var yyTok1 = [...]int8{ @@ -1334,7 +1334,7 @@ yydefault: yyDollar = yyS[yypt-3 : yypt+1] { numLit, _ := yyDollar[3].node.(*NumberLiteral) - dur := time.Duration(numLit.Val*1000) * time.Millisecond + dur := &NumberLiteral{Val: numLit.Val} yylex.(*parser).addOffset(yyDollar[1].node, dur) yyVAL.node = yyDollar[1].node } @@ -1342,42 +1342,51 @@ yydefault: yyDollar = yyS[yypt-4 : yypt+1] { numLit, _ := yyDollar[4].node.(*NumberLiteral) - dur := time.Duration(numLit.Val*1000) * time.Millisecond - yylex.(*parser).addOffset(yyDollar[1].node, -dur) + dur := &NumberLiteral{Val: numLit.Val * -1.0} + yylex.(*parser).addOffset(yyDollar[1].node, dur) yyVAL.node = yyDollar[1].node } case 70: yyDollar = yyS[yypt-3 : yypt+1] { - yylex.(*parser).unexpected("offset", "number or duration") - yyVAL.node = yyDollar[1].node + dur, _ := yyDollar[3].node.(*ParenExpr) + if dur.Type() != ValueTypeScalar { + yylex.(*parser).unexpected("offset", "time expression does not evaluate to a scalar") + } + yylex.(*parser).addOffset(yyDollar[1].node, dur) } case 71: + yyDollar = yyS[yypt-3 : yypt+1] + { + yylex.(*parser).unexpected("offset", "number or duration or time expression in parentheses") + yyVAL.node = yyDollar[1].node + } + case 72: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).setTimestamp(yyDollar[1].node, yyDollar[3].float) yyVAL.node = yyDollar[1].node } - case 72: + case 73: yyDollar = yyS[yypt-5 : yypt+1] { yylex.(*parser).setAtModifierPreprocessor(yyDollar[1].node, yyDollar[3].item) yyVAL.node = yyDollar[1].node } - case 73: + case 74: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("@", "timestamp") yyVAL.node = yyDollar[1].node } - case 76: + case 77: yyDollar = yyS[yypt-4 : yypt+1] { var errMsg string vs, ok := yyDollar[1].node.(*VectorSelector) if !ok { errMsg = "ranges only allowed for vector selectors" - } else if vs.OriginalOffset != 0 { + } else if vs.OriginalOffsetExpr != nil { errMsg = "no offset modifiers allowed before range" } else if vs.Timestamp != nil { errMsg = "no @ modifiers allowed before range" @@ -1395,7 +1404,7 @@ yydefault: EndPos: yylex.(*parser).lastClosing, } } - case 77: + case 78: yyDollar = yyS[yypt-6 : yypt+1] { numLitRange, _ := yyDollar[3].node.(*NumberLiteral) @@ -1407,7 +1416,7 @@ yydefault: EndPos: yyDollar[6].item.Pos + 1, } } - case 78: + case 79: yyDollar = yyS[yypt-5 : yypt+1] { numLitRange, _ := yyDollar[3].node.(*NumberLiteral) @@ -1418,31 +1427,31 @@ yydefault: EndPos: yyDollar[5].item.Pos + 1, } } - case 79: + case 80: yyDollar = yyS[yypt-6 : yypt+1] { yylex.(*parser).unexpected("subquery selector", "\"]\"") yyVAL.node = yyDollar[1].node } - case 80: + case 81: yyDollar = yyS[yypt-5 : yypt+1] { yylex.(*parser).unexpected("subquery selector", "number or duration or \"]\"") yyVAL.node = yyDollar[1].node } - case 81: + case 82: yyDollar = yyS[yypt-4 : yypt+1] { yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"") yyVAL.node = yyDollar[1].node } - case 82: + case 83: yyDollar = yyS[yypt-3 : yypt+1] { yylex.(*parser).unexpected("subquery selector", "number or duration") yyVAL.node = yyDollar[1].node } - case 83: + case 84: yyDollar = yyS[yypt-2 : yypt+1] { if nl, ok := yyDollar[2].node.(*NumberLiteral); ok { @@ -1455,7 +1464,7 @@ yydefault: yyVAL.node = &UnaryExpr{Op: yyDollar[1].item.Typ, Expr: yyDollar[2].node.(Expr), StartPos: yyDollar[1].item.Pos} } } - case 84: + case 85: yyDollar = yyS[yypt-2 : yypt+1] { vs := yyDollar[2].node.(*VectorSelector) @@ -1464,7 +1473,7 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 85: + case 86: yyDollar = yyS[yypt-1 : yypt+1] { vs := &VectorSelector{ @@ -1475,14 +1484,14 @@ yydefault: yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 86: + case 87: yyDollar = yyS[yypt-1 : yypt+1] { vs := yyDollar[1].node.(*VectorSelector) yylex.(*parser).assembleVectorSelector(vs) yyVAL.node = vs } - case 87: + case 88: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1490,7 +1499,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[3].item), } } - case 88: + case 89: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1498,7 +1507,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[4].item), } } - case 89: + case 90: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.node = &VectorSelector{ @@ -1506,7 +1515,7 @@ yydefault: PosRange: mergeRanges(&yyDollar[1].item, &yyDollar[2].item), } } - case 90: + case 91: yyDollar = yyS[yypt-3 : yypt+1] { if yyDollar[1].matchers != nil { @@ -1515,38 +1524,32 @@ yydefault: yyVAL.matchers = yyDollar[1].matchers } } - case 91: + case 92: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher} } - case 92: + case 93: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") yyVAL.matchers = yyDollar[1].matchers } - case 93: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) - } case 94: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) } case 95: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) + } + case 96: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.matcher = yylex.(*parser).newMetricNameMatcher(yyDollar[1].item) } - case 96: - yyDollar = yyS[yypt-3 : yypt+1] - { - yylex.(*parser).unexpected("label matching", "string") - yyVAL.matcher = nil - } case 97: yyDollar = yyS[yypt-3 : yypt+1] { @@ -1554,86 +1557,86 @@ yydefault: yyVAL.matcher = nil } case 98: + yyDollar = yyS[yypt-3 : yypt+1] + { + yylex.(*parser).unexpected("label matching", "string") + yyVAL.matcher = nil + } + case 99: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label matching", "label matching operator") yyVAL.matcher = nil } - case 99: + case 100: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("label matching", "identifier or \"}\"") yyVAL.matcher = nil } - case 100: + case 101: 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 101: + case 102: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.labels = yyDollar[1].labels } - case 126: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.labels = labels.New(yyDollar[2].lblList...) - } case 127: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.labels = labels.New(yyDollar[2].lblList...) } case 128: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] { - yyVAL.labels = labels.New() + yyVAL.labels = labels.New(yyDollar[2].lblList...) } case 129: - yyDollar = yyS[yypt-0 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.labels = labels.New() } case 130: + yyDollar = yyS[yypt-0 : yypt+1] + { + yyVAL.labels = labels.New() + } + case 131: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.lblList = append(yyDollar[1].lblList, yyDollar[3].label) } - case 131: + case 132: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.lblList = []labels.Label{yyDollar[1].label} } - case 132: + case 133: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label set", "\",\" or \"}\"") yyVAL.lblList = yyDollar[1].lblList } - case 133: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} - } case 134: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} } case 135: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} + } + case 136: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.label = labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val} } - case 136: - yyDollar = yyS[yypt-3 : yypt+1] - { - yylex.(*parser).unexpected("label set", "string") - yyVAL.label = labels.Label{} - } case 137: yyDollar = yyS[yypt-3 : yypt+1] { @@ -1641,18 +1644,24 @@ yydefault: yyVAL.label = labels.Label{} } case 138: + yyDollar = yyS[yypt-3 : yypt+1] + { + yylex.(*parser).unexpected("label set", "string") + yyVAL.label = labels.Label{} + } + case 139: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("label set", "\"=\"") yyVAL.label = labels.Label{} } - case 139: + case 140: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("label set", "identifier or \"}\"") yyVAL.label = labels.Label{} } - case 140: + case 141: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).generatedParserResult = &seriesDescription{ @@ -1660,33 +1669,33 @@ yydefault: values: yyDollar[2].series, } } - case 141: + case 142: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.series = []SequenceValue{} } - case 142: + case 143: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...) } - case 143: + case 144: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.series = yyDollar[1].series } - case 144: + case 145: yyDollar = yyS[yypt-1 : yypt+1] { yylex.(*parser).unexpected("series values", "") yyVAL.series = nil } - case 145: + case 146: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Omitted: true}} } - case 146: + case 147: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1694,12 +1703,12 @@ yydefault: yyVAL.series = append(yyVAL.series, SequenceValue{Omitted: true}) } } - case 147: + case 148: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Value: yyDollar[1].float}} } - case 148: + case 149: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1708,7 +1717,7 @@ yydefault: yyVAL.series = append(yyVAL.series, SequenceValue{Value: yyDollar[1].float}) } } - case 149: + case 150: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1718,12 +1727,12 @@ yydefault: yyDollar[1].float += yyDollar[2].float } } - case 150: + case 151: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.series = []SequenceValue{{Histogram: yyDollar[1].histogram}} } - case 151: + case 152: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.series = []SequenceValue{} @@ -1733,7 +1742,7 @@ yydefault: //$1 += $2 } } - case 152: + case 153: yyDollar = yyS[yypt-5 : yypt+1] { val, err := yylex.(*parser).histogramsIncreaseSeries(yyDollar[1].histogram, yyDollar[3].histogram, yyDollar[5].uint) @@ -1742,7 +1751,7 @@ yydefault: } yyVAL.series = val } - case 153: + case 154: yyDollar = yyS[yypt-5 : yypt+1] { val, err := yylex.(*parser).histogramsDecreaseSeries(yyDollar[1].histogram, yyDollar[3].histogram, yyDollar[5].uint) @@ -1751,7 +1760,7 @@ yydefault: } yyVAL.series = val } - case 154: + case 155: yyDollar = yyS[yypt-1 : yypt+1] { if yyDollar[1].item.Val != "stale" { @@ -1759,130 +1768,130 @@ yydefault: } yyVAL.float = math.Float64frombits(value.StaleNaN) } - case 157: - yyDollar = yyS[yypt-4 : yypt+1] - { - yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) - } case 158: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) } case 159: yyDollar = yyS[yypt-3 : yypt+1] { - m := yylex.(*parser).newMap() - yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) + yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&yyDollar[2].descriptors) } case 160: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] { m := yylex.(*parser).newMap() yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) } case 161: + yyDollar = yyS[yypt-2 : yypt+1] + { + m := yylex.(*parser).newMap() + yyVAL.histogram = yylex.(*parser).buildHistogramFromMap(&m) + } + case 162: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = *(yylex.(*parser).mergeMaps(&yyDollar[1].descriptors, &yyDollar[3].descriptors)) } - case 162: + case 163: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.descriptors = yyDollar[1].descriptors } - case 163: + case 164: yyDollar = yyS[yypt-2 : yypt+1] { yylex.(*parser).unexpected("histogram description", "histogram description key, e.g. buckets:[5 10 7]") } - case 164: - yyDollar = yyS[yypt-3 : yypt+1] - { - yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["schema"] = yyDollar[3].int - } case 165: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["sum"] = yyDollar[3].float + yyVAL.descriptors["schema"] = yyDollar[3].int } case 166: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["count"] = yyDollar[3].float + yyVAL.descriptors["sum"] = yyDollar[3].float } case 167: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["z_bucket"] = yyDollar[3].float + yyVAL.descriptors["count"] = yyDollar[3].float } case 168: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["z_bucket_w"] = yyDollar[3].float + yyVAL.descriptors["z_bucket"] = yyDollar[3].float } case 169: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["custom_values"] = yyDollar[3].bucket_set + yyVAL.descriptors["z_bucket_w"] = yyDollar[3].float } case 170: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["buckets"] = yyDollar[3].bucket_set + yyVAL.descriptors["custom_values"] = yyDollar[3].bucket_set } case 171: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["offset"] = yyDollar[3].int + yyVAL.descriptors["buckets"] = yyDollar[3].bucket_set } case 172: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["n_buckets"] = yyDollar[3].bucket_set + yyVAL.descriptors["offset"] = yyDollar[3].int } case 173: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["n_offset"] = yyDollar[3].int + yyVAL.descriptors["n_buckets"] = yyDollar[3].bucket_set } case 174: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.descriptors = yylex.(*parser).newMap() - yyVAL.descriptors["counter_reset_hint"] = yyDollar[3].item + yyVAL.descriptors["n_offset"] = yyDollar[3].int } case 175: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.bucket_set = yyDollar[2].bucket_set + yyVAL.descriptors = yylex.(*parser).newMap() + yyVAL.descriptors["counter_reset_hint"] = yyDollar[3].item } case 176: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.bucket_set = yyDollar[2].bucket_set } case 177: yyDollar = yyS[yypt-3 : yypt+1] { - yyVAL.bucket_set = append(yyDollar[1].bucket_set, yyDollar[3].float) + yyVAL.bucket_set = yyDollar[2].bucket_set } case 178: + yyDollar = yyS[yypt-3 : yypt+1] + { + yyVAL.bucket_set = append(yyDollar[1].bucket_set, yyDollar[3].float) + } + case 179: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.bucket_set = []float64{yyDollar[1].float} } - case 233: + case 234: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &NumberLiteral{ @@ -1890,7 +1899,7 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 234: + case 235: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -1904,12 +1913,12 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 235: + case 236: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val) } - case 236: + case 237: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -1920,17 +1929,17 @@ yydefault: } yyVAL.float = dur.Seconds() } - case 237: + case 238: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.float = yyDollar[2].float } - case 238: + case 239: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.float = -yyDollar[2].float } - case 241: + case 242: yyDollar = yyS[yypt-1 : yypt+1] { var err error @@ -1939,17 +1948,17 @@ yydefault: yylex.(*parser).addParseErrf(yyDollar[1].item.PositionRange(), "invalid repetition in series values: %s", err) } } - case 242: + case 243: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.int = -int64(yyDollar[2].uint) } - case 243: + case 244: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.int = int64(yyDollar[1].uint) } - case 244: + case 245: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.node = &StringLiteral{ @@ -1957,7 +1966,7 @@ yydefault: PosRange: yyDollar[1].item.PositionRange(), } } - case 245: + case 246: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.item = Item{ @@ -1966,7 +1975,7 @@ yydefault: Val: yylex.(*parser).unquoteString(yyDollar[1].item.Val), } } - case 246: + case 247: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.strings = nil diff --git a/promql/parser/parse.go b/promql/parser/parse.go index 9bf27264a8..6ccdfaf0d3 100644 --- a/promql/parser/parse.go +++ b/promql/parser/parse.go @@ -937,13 +937,13 @@ func (p *parser) newMetricNameMatcher(value Item) *labels.Matcher { } // addOffset is used to set the offset in the generated parser. -func (p *parser) addOffset(e Node, offset time.Duration) { - var orgoffsetp *time.Duration +func (p *parser) addOffset(e Node, offset Expr) { + var orgoffsetp *Expr var endPosp *posrange.Pos switch s := e.(type) { case *VectorSelector: - orgoffsetp = &s.OriginalOffset + orgoffsetp = &s.OriginalOffsetExpr endPosp = &s.PosRange.End case *MatrixSelector: vs, ok := s.VectorSelector.(*VectorSelector) @@ -951,10 +951,10 @@ func (p *parser) addOffset(e Node, offset time.Duration) { p.addParseErrf(e.PositionRange(), "ranges only allowed for vector selectors") return } - orgoffsetp = &vs.OriginalOffset + orgoffsetp = &vs.OriginalOffsetExpr endPosp = &s.EndPos case *SubqueryExpr: - orgoffsetp = &s.OriginalOffset + orgoffsetp = &s.OriginalOffsetExpr endPosp = &s.EndPos default: p.addParseErrf(e.PositionRange(), "offset modifier must be preceded by an instant vector selector or range vector selector or a subquery") @@ -963,7 +963,7 @@ func (p *parser) addOffset(e Node, offset time.Duration) { // it is already ensured by parseDuration func that there never will be a zero offset modifier switch { - case *orgoffsetp != 0: + case *orgoffsetp != nil: p.addParseErrf(e.PositionRange(), "offset may not be set multiple times") case orgoffsetp != nil: *orgoffsetp = offset diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index 3445fce067..47a2a4e8c6 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -1472,8 +1472,8 @@ var testExpr = []struct { { input: "foo offset 5m", expected: &VectorSelector{ - Name: "foo", - OriginalOffset: 5 * time.Minute, + Name: "foo", + OriginalOffsetExpr: &NumberLiteral{Val: float64(5 * time.Minute / time.Second)}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"), }, @@ -1486,8 +1486,8 @@ var testExpr = []struct { { input: "foo offset -7m", expected: &VectorSelector{ - Name: "foo", - OriginalOffset: -7 * time.Minute, + Name: "foo", + OriginalOffsetExpr: &NumberLiteral{Val: float64(-7 * time.Minute / time.Second)}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"), }, @@ -1500,8 +1500,8 @@ var testExpr = []struct { { input: `foo OFFSET 1h30m`, expected: &VectorSelector{ - Name: "foo", - OriginalOffset: 90 * time.Minute, + Name: "foo", + OriginalOffsetExpr: &NumberLiteral{Val: float64(90 * time.Minute / time.Second)}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"), }, @@ -1514,8 +1514,8 @@ var testExpr = []struct { { input: `foo OFFSET 1m30ms`, expected: &VectorSelector{ - Name: "foo", - OriginalOffset: time.Minute + 30*time.Millisecond, + Name: "foo", + OriginalOffsetExpr: &NumberLiteral{Val: 60.03}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"), }, @@ -1525,6 +1525,60 @@ var testExpr = []struct { }, }, }, + { + // 0 1 2 + // 123456789012345678901234567890 + input: `foo offset (scalar(vector(1)))`, + expected: &VectorSelector{ + Name: "foo", + OriginalOffsetExpr: &ParenExpr{ + Expr: &Call{ + Func: &Function{ + Name: "scalar", + ArgTypes: []ValueType{ValueTypeVector}, + ReturnType: ValueTypeScalar, + }, + Args: Expressions{ + &Call{ + Func: &Function{ + Name: "vector", + ArgTypes: []ValueType{ValueTypeScalar}, + ReturnType: ValueTypeVector, + }, + Args: Expressions{ + &NumberLiteral{ + PosRange: posrange.PositionRange{ + Start: 26, + End: 27, + }, + Val: 1.0, + }, + }, + PosRange: posrange.PositionRange{ + Start: 19, + End: 28, + }, + }, + }, + PosRange: posrange.PositionRange{ + Start: 12, + End: 29, + }, + }, + PosRange: posrange.PositionRange{ + Start: 11, + End: 30, + }, + }, + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"), + }, + PosRange: posrange.PositionRange{ + Start: 0, + End: 30, + }, + }, + }, { input: `foo @ 1603774568`, expected: &VectorSelector{ @@ -2064,8 +2118,8 @@ var testExpr = []struct { input: "test[5h] OFFSET 5m", expected: &MatrixSelector{ VectorSelector: &VectorSelector{ - Name: "test", - OriginalOffset: 5 * time.Minute, + Name: "test", + OriginalOffsetExpr: &NumberLiteral{Val: float64(5 * time.Minute / time.Second)}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "test"), }, @@ -2082,8 +2136,8 @@ var testExpr = []struct { input: "test[5d] OFFSET 10s", expected: &MatrixSelector{ VectorSelector: &VectorSelector{ - Name: "test", - OriginalOffset: 10 * time.Second, + Name: "test", + OriginalOffsetExpr: &NumberLiteral{Val: 10}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "test"), }, @@ -2100,8 +2154,8 @@ var testExpr = []struct { input: "test[5w] offset 2w", expected: &MatrixSelector{ VectorSelector: &VectorSelector{ - Name: "test", - OriginalOffset: 14 * 24 * time.Hour, + Name: "test", + OriginalOffsetExpr: &NumberLiteral{Val: float64(14 * 24 * time.Hour / time.Second)}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "test"), }, @@ -2118,8 +2172,8 @@ var testExpr = []struct { input: `test{a="b"}[5y] OFFSET 3d`, expected: &MatrixSelector{ VectorSelector: &VectorSelector{ - Name: "test", - OriginalOffset: 3 * 24 * time.Hour, + Name: "test", + OriginalOffsetExpr: &NumberLiteral{Val: float64(3 * 24 * time.Hour / time.Second)}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, "a", "b"), MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "test"), @@ -2137,8 +2191,8 @@ var testExpr = []struct { input: `test{a="b"}[5m] OFFSET 3600`, expected: &MatrixSelector{ VectorSelector: &VectorSelector{ - Name: "test", - OriginalOffset: 1 * time.Hour, + Name: "test", + OriginalOffsetExpr: &NumberLiteral{Val: float64(1 * time.Hour / time.Second)}, LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, "a", "b"), MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "test"), @@ -2355,6 +2409,11 @@ var testExpr = []struct { fail: true, errMsg: "unexpected end of input in offset, expected number or duration", }, + { + input: `some_metric[5m] OFFSET (vector(1))`, + fail: true, + errMsg: "time expression does not evaluate to a scalar", + }, { input: `some_metric OFFSET 1m[5m]`, fail: true, @@ -3267,9 +3326,9 @@ var testExpr = []struct { End: 38, }, }, - Range: 5 * time.Minute, - OriginalOffset: 4 * time.Minute, - EndPos: 53, + Range: 5 * time.Minute, + OriginalOffsetExpr: &NumberLiteral{Val: float64(4 * time.Minute / time.Second)}, + EndPos: 53, }, }, PosRange: posrange.PositionRange{ @@ -3413,7 +3472,7 @@ var testExpr = []struct { Start: 0, End: 21, }, - OriginalOffset: 1 * time.Minute, + OriginalOffsetExpr: &NumberLiteral{Val: float64(1 * time.Minute / time.Second)}, }, Range: 10 * time.Minute, Step: 5 * time.Second, @@ -3451,8 +3510,8 @@ var testExpr = []struct { Start: 0, End: 27, }, - Timestamp: makeInt64Pointer(123000), - OriginalOffset: 1 * time.Minute, + Timestamp: makeInt64Pointer(123000), + OriginalOffsetExpr: &NumberLiteral{Val: float64(1 * time.Minute / time.Second)}, }, Range: 10 * time.Minute, Step: 5 * time.Second, @@ -3471,8 +3530,8 @@ var testExpr = []struct { Start: 0, End: 27, }, - Timestamp: makeInt64Pointer(123000), - OriginalOffset: 1 * time.Minute, + Timestamp: makeInt64Pointer(123000), + OriginalOffsetExpr: &NumberLiteral{Val: float64(1 * time.Minute / time.Second)}, }, Range: 10 * time.Minute, Step: 5 * time.Second, @@ -3492,11 +3551,11 @@ var testExpr = []struct { End: 11, }, }, - Timestamp: makeInt64Pointer(123000), - OriginalOffset: 1 * time.Minute, - Range: 10 * time.Minute, - Step: 5 * time.Second, - EndPos: 35, + Timestamp: makeInt64Pointer(123000), + OriginalOffsetExpr: &NumberLiteral{Val: float64(1 * time.Minute / time.Second)}, + Range: 10 * time.Minute, + Step: 5 * time.Second, + EndPos: 35, }, }, { @@ -3575,9 +3634,9 @@ var testExpr = []struct { End: 21, }, }, - Range: 5 * time.Minute, - OriginalOffset: 10 * time.Minute, - EndPos: 37, + Range: 5 * time.Minute, + OriginalOffsetExpr: &NumberLiteral{Val: float64(10 * time.Minute / time.Second)}, + EndPos: 37, }, }, { @@ -3886,8 +3945,7 @@ var testExpr = []struct { Args: Expressions{ &MatrixSelector{ VectorSelector: &VectorSelector{ - Name: "http_request_counter_total", - OriginalOffset: 0, + Name: "http_request_counter_total", LabelMatchers: []*labels.Matcher{ MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "http_request_counter_total"), }, @@ -4006,6 +4064,7 @@ func TestParseExpressions(t *testing.T) { require.Equal(t, expected, expr, "error on input '%s'", test.input) } else { + require.Error(t, err, "expected an error on input '%s', got nil", test.input) require.ErrorContains(t, err, test.errMsg, "unexpected error on input '%s', expected '%s', got '%s'", test.input, test.errMsg, err.Error()) var errorList ParseErrors diff --git a/promql/parser/printer.go b/promql/parser/printer.go index afe755e7dd..3d2e17abd9 100644 --- a/promql/parser/printer.go +++ b/promql/parser/printer.go @@ -158,11 +158,8 @@ func (node *MatrixSelector) atOffset() (string, string) { // Copy the Vector selector before changing the offset vecSelector := node.VectorSelector.(*VectorSelector) offset := "" - switch { - case vecSelector.OriginalOffset > time.Duration(0): - offset = fmt.Sprintf(" offset %s", model.Duration(vecSelector.OriginalOffset)) - case vecSelector.OriginalOffset < time.Duration(0): - offset = fmt.Sprintf(" offset -%s", model.Duration(-vecSelector.OriginalOffset)) + if vecSelector.OriginalOffsetExpr != nil { + offset = fmt.Sprintf(" offset %s", timeExprString(vecSelector.OriginalOffsetExpr)) } at := "" switch { @@ -181,14 +178,14 @@ func (node *MatrixSelector) String() string { // Copy the Vector selector before changing the offset vecSelector := *node.VectorSelector.(*VectorSelector) // Do not print the @ and offset twice. - offsetVal, atVal, preproc := vecSelector.OriginalOffset, vecSelector.Timestamp, vecSelector.StartOrEnd - vecSelector.OriginalOffset = 0 + offsetExpr, atVal, preproc := vecSelector.OriginalOffsetExpr, vecSelector.Timestamp, vecSelector.StartOrEnd + vecSelector.OriginalOffsetExpr = nil vecSelector.Timestamp = nil vecSelector.StartOrEnd = 0 str := fmt.Sprintf("%s[%s]%s%s", vecSelector.String(), model.Duration(node.Range), at, offset) - vecSelector.OriginalOffset, vecSelector.Timestamp, vecSelector.StartOrEnd = offsetVal, atVal, preproc + vecSelector.OriginalOffsetExpr, vecSelector.Timestamp, vecSelector.StartOrEnd = offsetExpr, atVal, preproc return str } @@ -213,11 +210,8 @@ func (node *SubqueryExpr) getSubqueryTimeSuffix() string { step = model.Duration(node.Step).String() } offset := "" - switch { - case node.OriginalOffset > time.Duration(0): - offset = fmt.Sprintf(" offset %s", model.Duration(node.OriginalOffset)) - case node.OriginalOffset < time.Duration(0): - offset = fmt.Sprintf(" offset -%s", model.Duration(-node.OriginalOffset)) + if node.OriginalOffsetExpr != nil { + offset = fmt.Sprintf(" offset %s", timeExprString(node.OriginalOffsetExpr)) } at := "" switch { @@ -264,11 +258,8 @@ func (node *VectorSelector) String() string { labelStrings = append(labelStrings, matcher.String()) } offset := "" - switch { - case node.OriginalOffset > time.Duration(0): - offset = fmt.Sprintf(" offset %s", model.Duration(node.OriginalOffset)) - case node.OriginalOffset < time.Duration(0): - offset = fmt.Sprintf(" offset -%s", model.Duration(-node.OriginalOffset)) + if node.OriginalOffsetExpr != nil { + offset = fmt.Sprintf(" offset %s", timeExprString(node.OriginalOffsetExpr)) } at := "" switch { @@ -286,3 +277,15 @@ func (node *VectorSelector) String() string { sort.Strings(labelStrings) return fmt.Sprintf("%s{%s}%s%s", node.Name, strings.Join(labelStrings, ","), at, offset) } + +func timeExprString(e Expr) string { + if nl, ok := e.(*NumberLiteral); ok { + v, sign := nl.Val, "" + if nl.Val < 0 { + v = -1 * v + sign = "-" + } + return fmt.Sprintf("%s%s", sign, model.Duration(time.Duration(v)*time.Second)) + } + return e.String() +} diff --git a/promql/parser/printer_test.go b/promql/parser/printer_test.go index 0a557ad597..7f07274aaf 100644 --- a/promql/parser/printer_test.go +++ b/promql/parser/printer_test.go @@ -112,6 +112,11 @@ func TestExprString(t *testing.T) { { in: `a[1h:5m] offset 1m`, }, + { + in: `a[12m] offset (1m + 1m)`, + // TODO(krajorama): maybe handle time expressions special for numbers? + out: `a[12m] offset (60 + 60)`, + }, { in: `{__name__="a"}`, }, diff --git a/promql/promqltest/testdata/duration_arithmetic.test b/promql/promqltest/testdata/duration_arithmetic.test new file mode 100644 index 0000000000..28386510aa --- /dev/null +++ b/promql/promqltest/testdata/duration_arithmetic.test @@ -0,0 +1,36 @@ +# This file test requirements from +# https://github.com/prometheus/prometheus/issues/12318 +# We only supply float samples in the inputs and assume that complex type behave +# the same. + +load 1m + metric 0+1x60 + +# offset modifier. +# +# Regression test offset modifier has higher precedence. +# Value at 10m-5m and then plus 1. +eval instant at 10m metric offset 5m + 1 + {} 6 + +# Regression test offset modifier has higher precedence. +# Value at 10m-5m and then plus 60(s). +eval instant at 10m metric offset 5m + 1m + {} 65 + +# Value at 10m-(5m+1s) == 4m59s. +eval instant at 10m metric offset (5m + 1) + metric{} 4 + +# Value at 10m-(5m-120s) == 7m. +eval instant at 10m metric offset (5m - 120) + metric{} 7 + +# Value at 10m-(5m+1m) == 4m. +eval instant at 10m metric offset (5m + 1m) + metric{} 4 + +# The time() function is allowed on top level. +# Value at 10m-(1) == 9.59 +eval instant at 10m metric offset (time() != bool 0 + time() == bool 0) + metric{} 9