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