diff --git a/rules/ast/ast.go b/rules/ast/ast.go index 8797c8fde..a6f9e0195 100644 --- a/rules/ast/ast.go +++ b/rules/ast/ast.go @@ -215,6 +215,7 @@ type ( // A VectorSelector represents a metric name plus labelset. VectorSelector struct { labelMatchers metric.LabelMatchers + offset time.Duration // The series iterators are populated at query analysis time. iterators map[clientmodel.Fingerprint]local.SeriesIterator metrics map[clientmodel.Fingerprint]clientmodel.COWMetric @@ -261,6 +262,7 @@ type ( // Fingerprints are populated from label matchers at query analysis time. fingerprints clientmodel.Fingerprints interval time.Duration + offset time.Duration } ) @@ -561,8 +563,8 @@ func (node *VectorSelector) Eval(timestamp clientmodel.Timestamp) Vector { //// timer := v.stats.GetTimer(stats.GetValueAtTimeTime).Start() samples := Vector{} for fp, it := range node.iterators { - sampleCandidates := it.GetValueAtTime(timestamp) - samplePair := chooseClosestSample(sampleCandidates, timestamp) + sampleCandidates := it.GetValueAtTime(timestamp.Add(-node.offset)) + samplePair := chooseClosestSample(sampleCandidates, timestamp.Add(-node.offset)) if samplePair != nil { samples = append(samples, &Sample{ Metric: node.metrics[fp], @@ -823,8 +825,8 @@ func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp) Vector { // the selector. func (node *MatrixSelector) Eval(timestamp clientmodel.Timestamp) Matrix { interval := &metric.Interval{ - OldestInclusive: timestamp.Add(-node.interval), - NewestInclusive: timestamp, + OldestInclusive: timestamp.Add(-node.interval - node.offset), + NewestInclusive: timestamp.Add(-node.offset), } //// timer := v.stats.GetTimer(stats.GetRangeValuesTime).Start() @@ -835,6 +837,12 @@ func (node *MatrixSelector) Eval(timestamp clientmodel.Timestamp) Matrix { continue } + if node.offset != 0 { + for _, sp := range samplePairs { + sp.Timestamp = sp.Timestamp.Add(node.offset) + } + } + sampleStream := SampleStream{ Metric: node.metrics[fp], Values: samplePairs, @@ -910,9 +918,10 @@ func NewScalarLiteral(value clientmodel.SampleValue) *ScalarLiteral { // NewVectorSelector returns a (not yet evaluated) VectorSelector with // the given LabelSet. -func NewVectorSelector(m metric.LabelMatchers) *VectorSelector { +func NewVectorSelector(m metric.LabelMatchers, offset time.Duration) *VectorSelector { return &VectorSelector{ labelMatchers: m, + offset: offset, iterators: map[clientmodel.Fingerprint]local.SeriesIterator{}, metrics: map[clientmodel.Fingerprint]clientmodel.COWMetric{}, } @@ -1002,10 +1011,11 @@ func NewArithExpr(opType BinOpType, lhs Node, rhs Node) (Node, error) { // NewMatrixSelector returns a (not yet evaluated) MatrixSelector with // the given VectorSelector and Duration. -func NewMatrixSelector(vector *VectorSelector, interval time.Duration) *MatrixSelector { +func NewMatrixSelector(vector *VectorSelector, interval time.Duration, offset time.Duration) *MatrixSelector { return &MatrixSelector{ labelMatchers: vector.labelMatchers, interval: interval, + offset: offset, iterators: map[clientmodel.Fingerprint]local.SeriesIterator{}, metrics: map[clientmodel.Fingerprint]clientmodel.COWMetric{}, } diff --git a/rules/ast/query_analyzer.go b/rules/ast/query_analyzer.go index f606773d4..9807f7527 100644 --- a/rules/ast/query_analyzer.go +++ b/rules/ast/query_analyzer.go @@ -22,69 +22,80 @@ import ( "github.com/prometheus/prometheus/storage/local" ) -// FullRangeMap maps the fingerprint of a full range to the duration -// of the matrix selector it resulted from. -type FullRangeMap map[clientmodel.Fingerprint]time.Duration +// preloadTimes tracks which instants or ranges to preload for a set of +// fingerprints. One of these structs is collected for each offset by the query +// analyzer. +type preloadTimes struct { + // Instants require single samples to be loaded along the entire query + // range, with intervals between the samples corresponding to the query + // resolution. + instants map[clientmodel.Fingerprint]struct{} + // Ranges require loading a range of samples at each resolution step, + // stretching backwards from the current evaluation timestamp. The length of + // the range into the past is given by the duration, as in "foo[5m]". + ranges map[clientmodel.Fingerprint]time.Duration +} -// IntervalRangeMap is a set of fingerprints of interval ranges. -type IntervalRangeMap map[clientmodel.Fingerprint]bool - -// A QueryAnalyzer recursively traverses the AST to look for any nodes +// A queryAnalyzer recursively traverses the AST to look for any nodes // which will need data from the datastore. Instantiate with -// NewQueryAnalyzer. -type QueryAnalyzer struct { - // Values collected by query analysis. - // - // Full ranges always implicitly span a time range of: - // - start: query interval start - duration - // - end: query interval end - // - // This is because full ranges can only result from matrix selectors (like - // "foo[5m]"), which have said time-spanning behavior during a ranged query. - FullRanges FullRangeMap - // Interval ranges always implicitly span the whole query range. - IntervalRanges IntervalRangeMap +// newQueryAnalyzer. +type queryAnalyzer struct { + // Tracks one set of times to preload per offset that occurs in the query + // expression. + offsetPreloadTimes map[time.Duration]preloadTimes // The underlying storage to which the query will be applied. Needed for // extracting timeseries fingerprint information during query analysis. storage local.Storage } -// NewQueryAnalyzer returns a pointer to a newly instantiated -// QueryAnalyzer. The storage is needed to extract timeseries +// newQueryAnalyzer returns a pointer to a newly instantiated +// queryAnalyzer. The storage is needed to extract timeseries // fingerprint information during query analysis. -func NewQueryAnalyzer(storage local.Storage) *QueryAnalyzer { - return &QueryAnalyzer{ - FullRanges: FullRangeMap{}, - IntervalRanges: IntervalRangeMap{}, - storage: storage, +func newQueryAnalyzer(storage local.Storage) *queryAnalyzer { + return &queryAnalyzer{ + offsetPreloadTimes: map[time.Duration]preloadTimes{}, + storage: storage, } } -// Visit implements the Visitor interface. -func (analyzer *QueryAnalyzer) Visit(node Node) { +func (analyzer *queryAnalyzer) getPreloadTimes(offset time.Duration) preloadTimes { + if _, ok := analyzer.offsetPreloadTimes[offset]; !ok { + analyzer.offsetPreloadTimes[offset] = preloadTimes{ + instants: map[clientmodel.Fingerprint]struct{}{}, + ranges: map[clientmodel.Fingerprint]time.Duration{}, + } + } + return analyzer.offsetPreloadTimes[offset] +} + +// visit implements the visitor interface. +func (analyzer *queryAnalyzer) visit(node Node) { switch n := node.(type) { case *VectorSelector: + pt := analyzer.getPreloadTimes(n.offset) fingerprints := analyzer.storage.GetFingerprintsForLabelMatchers(n.labelMatchers) n.fingerprints = fingerprints for _, fp := range fingerprints { - // Only add the fingerprint to IntervalRanges if not yet present in FullRanges. - // Full ranges always contain more points and span more time than interval ranges. - if _, alreadyInFullRanges := analyzer.FullRanges[fp]; !alreadyInFullRanges { - analyzer.IntervalRanges[fp] = true + // Only add the fingerprint to the instants if not yet present in the + // ranges. Ranges always contain more points and span more time than + // instants for the same offset. + if _, alreadyInRanges := pt.ranges[fp]; !alreadyInRanges { + pt.instants[fp] = struct{}{} } n.metrics[fp] = analyzer.storage.GetMetricForFingerprint(fp) } case *MatrixSelector: + pt := analyzer.getPreloadTimes(n.offset) fingerprints := analyzer.storage.GetFingerprintsForLabelMatchers(n.labelMatchers) n.fingerprints = fingerprints for _, fp := range fingerprints { - if analyzer.FullRanges[fp] < n.interval { - analyzer.FullRanges[fp] = n.interval - // Delete the fingerprint from IntervalRanges. Full ranges always contain - // more points and span more time than interval ranges, so we don't need - // an interval range for the same fingerprint, should we have one. - delete(analyzer.IntervalRanges, fp) + if pt.ranges[fp] < n.interval { + pt.ranges[fp] = n.interval + // Delete the fingerprint from the instants. Ranges always contain more + // points and span more time than instants, so we don't need to track + // an instant for the same fingerprint, should we have one. + delete(pt.instants, fp) } n.metrics[fp] = analyzer.storage.GetMetricForFingerprint(fp) @@ -96,7 +107,7 @@ type iteratorInitializer struct { storage local.Storage } -func (i *iteratorInitializer) Visit(node Node) { +func (i *iteratorInitializer) visit(node Node) { switch n := node.(type) { case *VectorSelector: for _, fp := range n.fingerprints { @@ -113,34 +124,37 @@ func prepareInstantQuery(node Node, timestamp clientmodel.Timestamp, storage loc totalTimer := queryStats.GetTimer(stats.TotalEvalTime) analyzeTimer := queryStats.GetTimer(stats.QueryAnalysisTime).Start() - analyzer := NewQueryAnalyzer(storage) + analyzer := newQueryAnalyzer(storage) Walk(analyzer, node) analyzeTimer.Stop() preloadTimer := queryStats.GetTimer(stats.PreloadTime).Start() p := storage.NewPreloader() - for fp, rangeDuration := range analyzer.FullRanges { - if et := totalTimer.ElapsedTime(); et > *queryTimeout { - preloadTimer.Stop() - p.Close() - return nil, queryTimeoutError{et} + for offset, pt := range analyzer.offsetPreloadTimes { + ts := timestamp.Add(-offset) + for fp, rangeDuration := range pt.ranges { + if et := totalTimer.ElapsedTime(); et > *queryTimeout { + preloadTimer.Stop() + p.Close() + return nil, queryTimeoutError{et} + } + if err := p.PreloadRange(fp, ts.Add(-rangeDuration), ts, *stalenessDelta); err != nil { + preloadTimer.Stop() + p.Close() + return nil, err + } } - if err := p.PreloadRange(fp, timestamp.Add(-rangeDuration), timestamp, *stalenessDelta); err != nil { - preloadTimer.Stop() - p.Close() - return nil, err - } - } - for fp := range analyzer.IntervalRanges { - if et := totalTimer.ElapsedTime(); et > *queryTimeout { - preloadTimer.Stop() - p.Close() - return nil, queryTimeoutError{et} - } - if err := p.PreloadRange(fp, timestamp, timestamp, *stalenessDelta); err != nil { - preloadTimer.Stop() - p.Close() - return nil, err + for fp := range pt.instants { + if et := totalTimer.ElapsedTime(); et > *queryTimeout { + preloadTimer.Stop() + p.Close() + return nil, queryTimeoutError{et} + } + if err := p.PreloadRange(fp, ts, ts, *stalenessDelta); err != nil { + preloadTimer.Stop() + p.Close() + return nil, err + } } } preloadTimer.Stop() @@ -157,47 +171,51 @@ func prepareRangeQuery(node Node, start clientmodel.Timestamp, end clientmodel.T totalTimer := queryStats.GetTimer(stats.TotalEvalTime) analyzeTimer := queryStats.GetTimer(stats.QueryAnalysisTime).Start() - analyzer := NewQueryAnalyzer(storage) + analyzer := newQueryAnalyzer(storage) Walk(analyzer, node) analyzeTimer.Stop() preloadTimer := queryStats.GetTimer(stats.PreloadTime).Start() p := storage.NewPreloader() - for fp, rangeDuration := range analyzer.FullRanges { - if et := totalTimer.ElapsedTime(); et > *queryTimeout { - preloadTimer.Stop() - p.Close() - return nil, queryTimeoutError{et} - } - if err := p.PreloadRange(fp, start.Add(-rangeDuration), end, *stalenessDelta); err != nil { - preloadTimer.Stop() - p.Close() - return nil, err - } - /* - if interval < rangeDuration { - if err := p.GetMetricRange(fp, end, end.Sub(start)+rangeDuration); err != nil { - p.Close() - return nil, err - } - } else { - if err := p.GetMetricRangeAtInterval(fp, start, end, interval, rangeDuration); err != nil { - p.Close() - return nil, err - } + for offset, pt := range analyzer.offsetPreloadTimes { + offsetStart := start.Add(-offset) + offsetEnd := end.Add(-offset) + for fp, rangeDuration := range pt.ranges { + if et := totalTimer.ElapsedTime(); et > *queryTimeout { + preloadTimer.Stop() + p.Close() + return nil, queryTimeoutError{et} } - */ - } - for fp := range analyzer.IntervalRanges { - if et := totalTimer.ElapsedTime(); et > *queryTimeout { - preloadTimer.Stop() - p.Close() - return nil, queryTimeoutError{et} + if err := p.PreloadRange(fp, offsetStart.Add(-rangeDuration), offsetEnd, *stalenessDelta); err != nil { + preloadTimer.Stop() + p.Close() + return nil, err + } + /* + if interval < rangeDuration { + if err := p.GetMetricRange(fp, offsetEnd, offsetEnd.Sub(offsetStart)+rangeDuration); err != nil { + p.Close() + return nil, err + } + } else { + if err := p.GetMetricRangeAtInterval(fp, offsetStart, offsetEnd, interval, rangeDuration); err != nil { + p.Close() + return nil, err + } + } + */ } - if err := p.PreloadRange(fp, start, end, *stalenessDelta); err != nil { - preloadTimer.Stop() - p.Close() - return nil, err + for fp := range pt.instants { + if et := totalTimer.ElapsedTime(); et > *queryTimeout { + preloadTimer.Stop() + p.Close() + return nil, queryTimeoutError{et} + } + if err := p.PreloadRange(fp, offsetStart, offsetEnd, *stalenessDelta); err != nil { + preloadTimer.Stop() + p.Close() + return nil, err + } } } preloadTimer.Stop() diff --git a/rules/ast/walk.go b/rules/ast/walk.go index 1975b2d39..143120e8f 100644 --- a/rules/ast/walk.go +++ b/rules/ast/walk.go @@ -13,16 +13,16 @@ package ast -// Visitor is the interface for a Node visitor. -type Visitor interface { - Visit(node Node) +// visitor is the interface for a Node visitor. +type visitor interface { + visit(node Node) } // Walk does a depth-first traversal of the AST, starting at node, -// calling visitor.Visit for each encountered Node in the tree. -func Walk(visitor Visitor, node Node) { - visitor.Visit(node) +// calling visitor.visit for each encountered Node in the tree. +func Walk(v visitor, node Node) { + v.visit(node) for _, childNode := range node.Children() { - Walk(visitor, childNode) + Walk(v, childNode) } } diff --git a/rules/helpers.go b/rules/helpers.go index aa80a9e8e..1c6287dc1 100644 --- a/rules/helpers.go +++ b/rules/helpers.go @@ -110,22 +110,30 @@ func NewArithExpr(opTypeStr string, lhs ast.Node, rhs ast.Node) (ast.Node, error return expr, nil } -// NewMatrixSelector is a convenience function to create a new AST matrix selector. -func NewMatrixSelector(vector ast.Node, intervalStr string) (ast.MatrixNode, error) { - switch vector.(type) { - case *ast.VectorSelector: - { - break - } - default: - return nil, fmt.Errorf("intervals are currently only supported for vector selectors") +// NewVectorSelector is a convenience function to create a new AST vector selector. +func NewVectorSelector(m metric.LabelMatchers, offsetStr string) (ast.VectorNode, error) { + offset, err := utility.StringToDuration(offsetStr) + if err != nil { + return nil, err } + return ast.NewVectorSelector(m, offset), nil +} + +// NewMatrixSelector is a convenience function to create a new AST matrix selector. +func NewMatrixSelector(vector ast.Node, intervalStr string, offsetStr string) (ast.MatrixNode, error) { interval, err := utility.StringToDuration(intervalStr) if err != nil { return nil, err } - vectorSelector := vector.(*ast.VectorSelector) - return ast.NewMatrixSelector(vectorSelector, interval), nil + offset, err := utility.StringToDuration(offsetStr) + if err != nil { + return nil, err + } + vectorSelector, ok := vector.(*ast.VectorSelector) + if !ok { + return nil, fmt.Errorf("intervals are currently only supported for vector selectors") + } + return ast.NewMatrixSelector(vectorSelector, interval, offset), nil } func newLabelMatcher(matchTypeStr string, name clientmodel.LabelName, value clientmodel.LabelValue) (*metric.LabelMatcher, error) { diff --git a/rules/lexer.l b/rules/lexer.l index 83577f175..82c900cff 100644 --- a/rules/lexer.l +++ b/rules/lexer.l @@ -80,6 +80,7 @@ DESCRIPTION|description return DESCRIPTION PERMANENT|permanent return PERMANENT BY|by return GROUP_OP KEEPING_EXTRA|keeping_extra return KEEPING_EXTRA +OFFSET|offset return OFFSET AVG|SUM|MAX|MIN|COUNT lval.str = lexer.token(); return AGGR_OP avg|sum|max|min|count lval.str = strings.ToUpper(lexer.token()); return AGGR_OP \<|>|AND|OR|and|or lval.str = strings.ToUpper(lexer.token()); return CMP_OP diff --git a/rules/lexer.l.go b/rules/lexer.l.go index d8a1d42f9..82706f65a 100644 --- a/rules/lexer.l.go +++ b/rules/lexer.l.go @@ -56,7 +56,7 @@ yystate0: case 0: // start condition: INITIAL goto yystart1 case 1: // start condition: S_COMMENTS - goto yystart153 + goto yystart162 } goto yystate0 // silence unused label error @@ -108,46 +108,46 @@ yystart1: case c == 'O': goto yystate74 case c == 'P': - goto yystate75 + goto yystate80 case c == 'S': - goto yystate84 + goto yystate89 case c == 'W': - goto yystate91 + goto yystate96 case c == '\'': goto yystate9 case c == '\t' || c == '\n' || c == '\r' || c == ' ': goto yystate2 case c == 'a': - goto yystate95 + goto yystate100 case c == 'b': - goto yystate102 - case c == 'c': - goto yystate103 - case c == 'd': goto yystate107 + case c == 'c': + goto yystate108 + case c == 'd': + goto yystate112 case c == 'f': - goto yystate117 + goto yystate122 case c == 'i': - goto yystate119 + goto yystate124 case c == 'k': - goto yystate120 + goto yystate125 case c == 'm': - goto yystate132 + goto yystate137 case c == 'o': - goto yystate135 + goto yystate140 case c == 'p': - goto yystate136 + goto yystate145 case c == 's': - goto yystate144 + goto yystate153 case c == 'w': - goto yystate150 + goto yystate159 case c >= '0' && c <= '9': goto yystate21 } yystate2: c = lexer.getChar() - goto yyrule27 + goto yyrule28 yystate3: c = lexer.getChar() @@ -160,7 +160,7 @@ yystate3: yystate4: c = lexer.getChar() - goto yyrule17 + goto yyrule18 yystate5: c = lexer.getChar() @@ -177,7 +177,7 @@ yystate5: yystate6: c = lexer.getChar() - goto yyrule24 + goto yyrule25 yystate7: c = lexer.getChar() @@ -190,7 +190,7 @@ yystate7: yystate8: c = lexer.getChar() - goto yyrule19 + goto yyrule20 yystate9: c = lexer.getChar() @@ -207,7 +207,7 @@ yystate9: yystate10: c = lexer.getChar() - goto yyrule25 + goto yyrule26 yystate11: c = lexer.getChar() @@ -220,17 +220,17 @@ yystate11: yystate12: c = lexer.getChar() - goto yyrule26 + goto yyrule27 yystate13: c = lexer.getChar() - goto yyrule18 + goto yyrule19 yystate14: c = lexer.getChar() switch { default: - goto yyrule18 + goto yyrule19 case c >= '0' && c <= '9': goto yystate15 } @@ -239,7 +239,7 @@ yystate15: c = lexer.getChar() switch { default: - goto yyrule23 + goto yyrule24 case c == '.': goto yystate16 case c >= '0' && c <= '9': @@ -250,7 +250,7 @@ yystate16: c = lexer.getChar() switch { default: - goto yyrule23 + goto yyrule24 case c >= '0' && c <= '9': goto yystate16 } @@ -259,7 +259,7 @@ yystate17: c = lexer.getChar() switch { default: - goto yyrule19 + goto yyrule20 case c == '*': goto yystate18 case c == '/': @@ -289,7 +289,7 @@ yystate21: c = lexer.getChar() switch { default: - goto yyrule23 + goto yyrule24 case c == '.': goto yystate16 case c == 'd' || c == 'h' || c == 'm' || c == 's' || c == 'w' || c == 'y': @@ -300,13 +300,13 @@ yystate21: yystate22: c = lexer.getChar() - goto yyrule20 + goto yyrule21 yystate23: c = lexer.getChar() switch { default: - goto yyrule22 + goto yyrule23 case c >= '0' && c <= ':' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate23 } @@ -315,7 +315,7 @@ yystate24: c = lexer.getChar() switch { default: - goto yyrule16 + goto yyrule17 case c == '=': goto yystate4 } @@ -324,7 +324,7 @@ yystate25: c = lexer.getChar() switch { default: - goto yyrule26 + goto yyrule27 case c == '=' || c == '~': goto yystate4 } @@ -333,7 +333,7 @@ yystate26: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'L': @@ -350,7 +350,7 @@ yystate27: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': @@ -361,7 +361,7 @@ yystate28: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'E': @@ -374,7 +374,7 @@ yystate29: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'R': @@ -387,7 +387,7 @@ yystate30: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'T': @@ -411,7 +411,7 @@ yystate32: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'D': @@ -424,7 +424,7 @@ yystate33: c = lexer.getChar() switch { default: - goto yyrule16 + goto yyrule17 case c == ':': goto yystate23 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': @@ -435,7 +435,7 @@ yystate34: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'G': @@ -448,7 +448,7 @@ yystate35: c = lexer.getChar() switch { default: - goto yyrule14 + goto yyrule15 case c == ':': goto yystate23 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': @@ -459,7 +459,7 @@ yystate36: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'Y': @@ -483,7 +483,7 @@ yystate38: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'O': @@ -496,7 +496,7 @@ yystate39: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'U': @@ -509,7 +509,7 @@ yystate40: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'N': @@ -522,7 +522,7 @@ yystate41: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'T': @@ -535,7 +535,7 @@ yystate42: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'E': @@ -548,7 +548,7 @@ yystate43: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'S': @@ -561,7 +561,7 @@ yystate44: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'C': @@ -574,7 +574,7 @@ yystate45: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'R': @@ -587,7 +587,7 @@ yystate46: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'I': @@ -600,7 +600,7 @@ yystate47: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'P': @@ -613,7 +613,7 @@ yystate48: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'T': @@ -626,7 +626,7 @@ yystate49: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'I': @@ -639,7 +639,7 @@ yystate50: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'O': @@ -652,7 +652,7 @@ yystate51: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'N': @@ -676,7 +676,7 @@ yystate53: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'O': @@ -689,7 +689,7 @@ yystate54: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'R': @@ -713,7 +713,7 @@ yystate56: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'F': @@ -737,7 +737,7 @@ yystate58: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'E': @@ -750,7 +750,7 @@ yystate59: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'E': @@ -763,7 +763,7 @@ yystate60: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'P': @@ -776,7 +776,7 @@ yystate61: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'I': @@ -789,7 +789,7 @@ yystate62: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'N': @@ -802,7 +802,7 @@ yystate63: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'G': @@ -815,7 +815,7 @@ yystate64: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == '_': @@ -828,7 +828,7 @@ yystate65: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'E': @@ -841,7 +841,7 @@ yystate66: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'X': @@ -854,7 +854,7 @@ yystate67: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'T': @@ -867,7 +867,7 @@ yystate68: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'R': @@ -880,7 +880,7 @@ yystate69: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'A': @@ -904,7 +904,7 @@ yystate71: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'A': @@ -919,7 +919,7 @@ yystate72: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'X': @@ -932,7 +932,7 @@ yystate73: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'N': @@ -945,12 +945,14 @@ yystate74: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 + case c == 'F': + goto yystate75 case c == 'R': goto yystate33 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Q' || c >= 'S' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'E' || c >= 'G' && c <= 'Q' || c >= 'S' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } @@ -958,12 +960,12 @@ yystate75: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'E': + case c == 'F': goto yystate76 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'D' || c >= 'F' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'E' || c >= 'G' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } @@ -971,12 +973,12 @@ yystate76: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'R': + case c == 'S': goto yystate77 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Q' || c >= 'S' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'R' || c >= 'T' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } @@ -984,12 +986,12 @@ yystate77: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'M': + case c == 'E': goto yystate78 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'L' || c >= 'N' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'D' || c >= 'F' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } @@ -997,12 +999,12 @@ yystate78: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'A': + case c == 'T': goto yystate79 - case c >= '0' && c <= '9' || c >= 'B' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'S' || c >= 'U' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } @@ -1010,12 +1012,10 @@ yystate79: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule14 case c == ':': goto yystate23 - case c == 'N': - goto yystate80 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'M' || c >= 'O' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } @@ -1023,7 +1023,7 @@ yystate80: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'E': @@ -1036,12 +1036,12 @@ yystate81: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'N': + case c == 'R': goto yystate82 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'M' || c >= 'O' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Q' || c >= 'S' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } @@ -1049,16 +1049,81 @@ yystate82: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'T': + case c == 'M': goto yystate83 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'S' || c >= 'U' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'L' || c >= 'N' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } yystate83: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'A': + goto yystate84 + case c >= '0' && c <= '9' || c >= 'B' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate84: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'N': + goto yystate85 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'M' || c >= 'O' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate85: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'E': + goto yystate86 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'D' || c >= 'F' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate86: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'N': + goto yystate87 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'M' || c >= 'O' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate87: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'T': + goto yystate88 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'S' || c >= 'U' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate88: c = lexer.getChar() switch { default: @@ -1069,85 +1134,85 @@ yystate83: goto yystate27 } -yystate84: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'U': - goto yystate85 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'T' || c >= 'V' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': - goto yystate27 - } - -yystate85: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'M': - goto yystate86 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'L' || c >= 'N' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': - goto yystate27 - } - -yystate86: - c = lexer.getChar() - switch { - default: - goto yyrule14 - case c == ':': - goto yystate23 - case c == 'M': - goto yystate87 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'L' || c >= 'N' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': - goto yystate27 - } - -yystate87: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'A': - goto yystate88 - case c >= '0' && c <= '9' || c >= 'B' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': - goto yystate27 - } - -yystate88: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'R': - goto yystate89 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Q' || c >= 'S' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': - goto yystate27 - } - yystate89: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'Y': + case c == 'U': goto yystate90 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'X' || c == 'Z' || c == '_' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'T' || c >= 'V' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } yystate90: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'M': + goto yystate91 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'L' || c >= 'N' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate91: + c = lexer.getChar() + switch { + default: + goto yyrule15 + case c == ':': + goto yystate23 + case c == 'M': + goto yystate92 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'L' || c >= 'N' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate92: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'A': + goto yystate93 + case c >= '0' && c <= '9' || c >= 'B' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate93: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'R': + goto yystate94 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Q' || c >= 'S' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate94: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'Y': + goto yystate95 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'X' || c == 'Z' || c == '_' || c >= 'a' && c <= 'z': + goto yystate27 + } + +yystate95: c = lexer.getChar() switch { default: @@ -1158,46 +1223,46 @@ yystate90: goto yystate27 } -yystate91: +yystate96: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'I': - goto yystate92 + goto yystate97 case c >= '0' && c <= '9' || c >= 'A' && c <= 'H' || c >= 'J' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } -yystate92: +yystate97: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'T': - goto yystate93 + goto yystate98 case c >= '0' && c <= '9' || c >= 'A' && c <= 'S' || c >= 'U' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } -yystate93: +yystate98: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'H': - goto yystate94 + goto yystate99 case c >= '0' && c <= '9' || c >= 'A' && c <= 'G' || c >= 'I' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } -yystate94: +yystate99: c = lexer.getChar() switch { default: @@ -1208,54 +1273,54 @@ yystate94: goto yystate27 } -yystate95: +yystate100: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'l': - goto yystate96 + goto yystate101 case c == 'n': - goto yystate99 + goto yystate104 case c == 'v': - goto yystate100 + goto yystate105 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'k' || c == 'm' || c >= 'o' && c <= 'u' || c >= 'w' && c <= 'z': goto yystate27 } -yystate96: +yystate101: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'e': - goto yystate97 + goto yystate102 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': goto yystate27 } -yystate97: +yystate102: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'r': - goto yystate98 + goto yystate103 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': goto yystate27 } -yystate98: +yystate103: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 't': @@ -1264,11 +1329,11 @@ yystate98: goto yystate27 } -yystate99: +yystate104: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'd': @@ -1277,35 +1342,35 @@ yystate99: goto yystate27 } -yystate100: +yystate105: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'g': - goto yystate101 + goto yystate106 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'f' || c >= 'h' && c <= 'z': goto yystate27 } -yystate101: +yystate106: c = lexer.getChar() switch { default: - goto yyrule15 + goto yyrule16 case c == ':': goto yystate23 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z': goto yystate27 } -yystate102: +yystate107: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'y': @@ -1314,81 +1379,16 @@ yystate102: goto yystate27 } -yystate103: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'o': - goto yystate104 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'n' || c >= 'p' && c <= 'z': - goto yystate27 - } - -yystate104: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'u': - goto yystate105 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 't' || c >= 'v' && c <= 'z': - goto yystate27 - } - -yystate105: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'n': - goto yystate106 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': - goto yystate27 - } - -yystate106: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 't': - goto yystate101 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': - goto yystate27 - } - -yystate107: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'e': - goto yystate108 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': - goto yystate27 - } - yystate108: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 's': + case c == 'o': goto yystate109 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'r' || c >= 't' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'n' || c >= 'p' && c <= 'z': goto yystate27 } @@ -1396,12 +1396,12 @@ yystate109: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'c': + case c == 'u': goto yystate110 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c == 'a' || c == 'b' || c >= 'd' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 't' || c >= 'v' && c <= 'z': goto yystate27 } @@ -1409,12 +1409,12 @@ yystate110: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'r': + case c == 'n': goto yystate111 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': goto yystate27 } @@ -1422,12 +1422,12 @@ yystate111: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'i': - goto yystate112 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'h' || c >= 'j' && c <= 'z': + case c == 't': + goto yystate106 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': goto yystate27 } @@ -1435,12 +1435,12 @@ yystate112: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'p': + case c == 'e': goto yystate113 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'o' || c >= 'q' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': goto yystate27 } @@ -1448,12 +1448,12 @@ yystate113: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 't': + case c == 's': goto yystate114 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'r' || c >= 't' && c <= 'z': goto yystate27 } @@ -1461,12 +1461,12 @@ yystate114: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'i': + case c == 'c': goto yystate115 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'h' || c >= 'j' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c == 'a' || c == 'b' || c >= 'd' && c <= 'z': goto yystate27 } @@ -1474,12 +1474,12 @@ yystate115: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'o': + case c == 'r': goto yystate116 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'n' || c >= 'p' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': goto yystate27 } @@ -1487,7 +1487,72 @@ yystate116: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'i': + goto yystate117 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'h' || c >= 'j' && c <= 'z': + goto yystate27 + } + +yystate117: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'p': + goto yystate118 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'o' || c >= 'q' && c <= 'z': + goto yystate27 + } + +yystate118: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 't': + goto yystate119 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': + goto yystate27 + } + +yystate119: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'i': + goto yystate120 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'h' || c >= 'j' && c <= 'z': + goto yystate27 + } + +yystate120: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'o': + goto yystate121 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'n' || c >= 'p' && c <= 'z': + goto yystate27 + } + +yystate121: + c = lexer.getChar() + switch { + default: + goto yyrule22 case c == ':': goto yystate23 case c == 'n': @@ -1496,24 +1561,24 @@ yystate116: goto yystate27 } -yystate117: +yystate122: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'o': - goto yystate118 + goto yystate123 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'n' || c >= 'p' && c <= 'z': goto yystate27 } -yystate118: +yystate123: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'r': @@ -1522,11 +1587,11 @@ yystate118: goto yystate27 } -yystate119: +yystate124: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'f': @@ -1535,81 +1600,16 @@ yystate119: goto yystate27 } -yystate120: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'e': - goto yystate121 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': - goto yystate27 - } - -yystate121: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'e': - goto yystate122 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': - goto yystate27 - } - -yystate122: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'p': - goto yystate123 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'o' || c >= 'q' && c <= 'z': - goto yystate27 - } - -yystate123: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'i': - goto yystate124 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'h' || c >= 'j' && c <= 'z': - goto yystate27 - } - -yystate124: - c = lexer.getChar() - switch { - default: - goto yyrule21 - case c == ':': - goto yystate23 - case c == 'n': - goto yystate125 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': - goto yystate27 - } - yystate125: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'g': + case c == 'e': goto yystate126 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'f' || c >= 'h' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': goto yystate27 } @@ -1617,12 +1617,12 @@ yystate126: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == '_': + case c == 'e': goto yystate127 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': goto yystate27 } @@ -1630,12 +1630,12 @@ yystate127: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'e': + case c == 'p': goto yystate128 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'o' || c >= 'q' && c <= 'z': goto yystate27 } @@ -1643,12 +1643,12 @@ yystate128: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'x': + case c == 'i': goto yystate129 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'w' || c == 'y' || c == 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'h' || c >= 'j' && c <= 'z': goto yystate27 } @@ -1656,12 +1656,12 @@ yystate129: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 't': + case c == 'n': goto yystate130 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': goto yystate27 } @@ -1669,12 +1669,12 @@ yystate130: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'r': + case c == 'g': goto yystate131 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'f' || c >= 'h' && c <= 'z': goto yystate27 } @@ -1682,12 +1682,12 @@ yystate131: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'a': - goto yystate70 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'b' && c <= 'z': + case c == '_': + goto yystate132 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z': goto yystate27 } @@ -1695,14 +1695,12 @@ yystate132: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'a': + case c == 'e': goto yystate133 - case c == 'i': - goto yystate134 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'b' && c <= 'h' || c >= 'j' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': goto yystate27 } @@ -1710,11 +1708,11 @@ yystate133: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'x': - goto yystate101 + goto yystate134 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'w' || c == 'y' || c == 'z': goto yystate27 } @@ -1723,12 +1721,12 @@ yystate134: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'n': - goto yystate101 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': + case c == 't': + goto yystate135 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': goto yystate27 } @@ -1736,11 +1734,11 @@ yystate135: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 case c == 'r': - goto yystate33 + goto yystate136 case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': goto yystate27 } @@ -1749,12 +1747,12 @@ yystate136: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'e': - goto yystate137 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': + case c == 'a': + goto yystate70 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'b' && c <= 'z': goto yystate27 } @@ -1762,12 +1760,14 @@ yystate137: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'r': + case c == 'a': goto yystate138 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': + case c == 'i': + goto yystate139 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'b' && c <= 'h' || c >= 'j' && c <= 'z': goto yystate27 } @@ -1775,12 +1775,12 @@ yystate138: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'm': - goto yystate139 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'l' || c >= 'n' && c <= 'z': + case c == 'x': + goto yystate106 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'w' || c == 'y' || c == 'z': goto yystate27 } @@ -1788,12 +1788,12 @@ yystate139: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'a': - goto yystate140 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'b' && c <= 'z': + case c == 'n': + goto yystate106 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': goto yystate27 } @@ -1801,12 +1801,14 @@ yystate140: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'n': + case c == 'f': goto yystate141 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': + case c == 'r': + goto yystate33 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'e' || c >= 'g' && c <= 'q' || c >= 's' && c <= 'z': goto yystate27 } @@ -1814,12 +1816,12 @@ yystate141: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'e': + case c == 'f': goto yystate142 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'e' || c >= 'g' && c <= 'z': goto yystate27 } @@ -1827,12 +1829,12 @@ yystate142: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'n': + case c == 's': goto yystate143 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'r' || c >= 't' && c <= 'z': goto yystate27 } @@ -1840,12 +1842,12 @@ yystate143: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 't': - goto yystate83 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': + case c == 'e': + goto yystate144 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': goto yystate27 } @@ -1853,12 +1855,12 @@ yystate144: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'u': - goto yystate145 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 't' || c >= 'v' && c <= 'z': + case c == 't': + goto yystate79 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': goto yystate27 } @@ -1866,12 +1868,12 @@ yystate145: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'm': + case c == 'e': goto yystate146 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'l' || c >= 'n' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': goto yystate27 } @@ -1879,12 +1881,12 @@ yystate146: c = lexer.getChar() switch { default: - goto yyrule15 + goto yyrule22 case c == ':': goto yystate23 - case c == 'm': + case c == 'r': goto yystate147 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'l' || c >= 'n' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': goto yystate27 } @@ -1892,12 +1894,12 @@ yystate147: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'a': + case c == 'm': goto yystate148 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'b' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'l' || c >= 'n' && c <= 'z': goto yystate27 } @@ -1905,12 +1907,12 @@ yystate148: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'r': + case c == 'a': goto yystate149 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'b' && c <= 'z': goto yystate27 } @@ -1918,12 +1920,12 @@ yystate149: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'y': - goto yystate90 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'x' || c == 'z': + case c == 'n': + goto yystate150 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': goto yystate27 } @@ -1931,12 +1933,12 @@ yystate150: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'i': + case c == 'e': goto yystate151 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'h' || c >= 'j' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'z': goto yystate27 } @@ -1944,12 +1946,12 @@ yystate151: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 't': + case c == 'n': goto yystate152 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'm' || c >= 'o' && c <= 'z': goto yystate27 } @@ -1957,42 +1959,159 @@ yystate152: c = lexer.getChar() switch { default: - goto yyrule21 + goto yyrule22 case c == ':': goto yystate23 - case c == 'h': - goto yystate94 - case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'g' || c >= 'i' && c <= 'z': + case c == 't': + goto yystate88 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': goto yystate27 } - goto yystate153 // silence unused label error yystate153: c = lexer.getChar() -yystart153: switch { default: - goto yyabort - case c == '*': - goto yystate155 - case c >= '\x01' && c <= ')' || c >= '+' && c <= 'ÿ': + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'u': goto yystate154 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 't' || c >= 'v' && c <= 'z': + goto yystate27 } yystate154: c = lexer.getChar() - goto yyrule3 + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'm': + goto yystate155 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'l' || c >= 'n' && c <= 'z': + goto yystate27 + } yystate155: c = lexer.getChar() switch { default: - goto yyrule3 - case c == '/': + goto yyrule16 + case c == ':': + goto yystate23 + case c == 'm': goto yystate156 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'l' || c >= 'n' && c <= 'z': + goto yystate27 } yystate156: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'a': + goto yystate157 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'b' && c <= 'z': + goto yystate27 + } + +yystate157: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'r': + goto yystate158 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'q' || c >= 's' && c <= 'z': + goto yystate27 + } + +yystate158: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'y': + goto yystate95 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'x' || c == 'z': + goto yystate27 + } + +yystate159: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'i': + goto yystate160 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'h' || c >= 'j' && c <= 'z': + goto yystate27 + } + +yystate160: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 't': + goto yystate161 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 's' || c >= 'u' && c <= 'z': + goto yystate27 + } + +yystate161: + c = lexer.getChar() + switch { + default: + goto yyrule22 + case c == ':': + goto yystate23 + case c == 'h': + goto yystate99 + case c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'g' || c >= 'i' && c <= 'z': + goto yystate27 + } + + goto yystate162 // silence unused label error +yystate162: + c = lexer.getChar() +yystart162: + switch { + default: + goto yyabort + case c == '*': + goto yystate164 + case c >= '\x01' && c <= ')' || c >= '+' && c <= 'ÿ': + goto yystate163 + } + +yystate163: + c = lexer.getChar() + goto yyrule3 + +yystate164: + c = lexer.getChar() + switch { + default: + goto yyrule3 + case c == '/': + goto yystate165 + } + +yystate165: c = lexer.getChar() goto yyrule2 @@ -2052,61 +2171,65 @@ yyrule13: // KEEPING_EXTRA|keeping_extra { return KEEPING_EXTRA } -yyrule14: // AVG|SUM|MAX|MIN|COUNT +yyrule14: // OFFSET|offset + { + return OFFSET + } +yyrule15: // AVG|SUM|MAX|MIN|COUNT { lval.str = lexer.token() return AGGR_OP goto yystate0 } -yyrule15: // avg|sum|max|min|count +yyrule16: // avg|sum|max|min|count { lval.str = strings.ToUpper(lexer.token()) return AGGR_OP goto yystate0 } -yyrule16: // \<|>|AND|OR|and|or +yyrule17: // \<|>|AND|OR|and|or { lval.str = strings.ToUpper(lexer.token()) return CMP_OP goto yystate0 } -yyrule17: // ==|!=|>=|<=|=~|!~ +yyrule18: // ==|!=|>=|<=|=~|!~ { lval.str = lexer.token() return CMP_OP goto yystate0 } -yyrule18: // [+\-] +yyrule19: // [+\-] { lval.str = lexer.token() return ADDITIVE_OP goto yystate0 } -yyrule19: // [*/%] +yyrule20: // [*/%] { lval.str = lexer.token() return MULT_OP goto yystate0 } -yyrule20: // {D}+{U} +yyrule21: // {D}+{U} { lval.str = lexer.token() return DURATION goto yystate0 } -yyrule21: // {L}({L}|{D})* +yyrule22: // {L}({L}|{D})* { lval.str = lexer.token() return IDENTIFIER goto yystate0 } -yyrule22: // {M}({M}|{D})* +yyrule23: // {M}({M}|{D})* { lval.str = lexer.token() return METRICNAME goto yystate0 } -yyrule23: // \-?{D}+(\.{D}*)? +yyrule24: // \-?{D}+(\.{D}*)? { num, err := strconv.ParseFloat(lexer.token(), 64) if err != nil && err.(*strconv.NumError).Err == strconv.ErrSyntax { @@ -2115,23 +2238,23 @@ yyrule23: // \-?{D}+(\.{D}*)? lval.num = clientmodel.SampleValue(num) return NUMBER } -yyrule24: // \"(\\.|[^\\"])*\" +yyrule25: // \"(\\.|[^\\"])*\" { lval.str = lexer.token()[1 : len(lexer.token())-1] return STRING goto yystate0 } -yyrule25: // \'(\\.|[^\\'])*\' +yyrule26: // \'(\\.|[^\\'])*\' { lval.str = lexer.token()[1 : len(lexer.token())-1] return STRING goto yystate0 } -yyrule26: // [{}\[\]()=,] +yyrule27: // [{}\[\]()=,] { return int(lexer.buf[0]) } -yyrule27: // [\t\n\r ] +yyrule28: // [\t\n\r ] { /* gobble up any whitespace */ goto yystate0 diff --git a/rules/parser.y b/rules/parser.y index af6e06941..b0c11c1b9 100644 --- a/rules/parser.y +++ b/rules/parser.y @@ -42,7 +42,7 @@ %token IDENTIFIER STRING DURATION METRICNAME %token NUMBER -%token PERMANENT GROUP_OP KEEPING_EXTRA +%token PERMANENT GROUP_OP KEEPING_EXTRA OFFSET %token AGGR_OP CMP_OP ADDITIVE_OP MULT_OP %token ALERT IF FOR WITH SUMMARY DESCRIPTION @@ -53,7 +53,7 @@ %type label_match_list label_matches %type rule_expr func_arg %type qualifier extra_labels_opts -%type for_duration metric_name label_match_type +%type for_duration metric_name label_match_type offset_opts %right '=' %left CMP_OP @@ -152,17 +152,28 @@ label_match_type : '=' { $$ = $1 } ; +offset_opts : /* empty */ + { $$ = "0s" } + | OFFSET DURATION + { $$ = $2 } + ; + rule_expr : '(' rule_expr ')' { $$ = $2 } - | '{' label_match_list '}' - { $$ = ast.NewVectorSelector($2) } - | metric_name label_matches + | '{' label_match_list '}' offset_opts + { + var err error + $$, err = NewVectorSelector($2, $4) + if err != nil { yylex.Error(err.Error()); return 1 } + } + | metric_name label_matches offset_opts { var err error m, err := metric.NewLabelMatcher(metric.Equal, clientmodel.MetricNameLabel, clientmodel.LabelValue($1)) if err != nil { yylex.Error(err.Error()); return 1 } $2 = append($2, m) - $$ = ast.NewVectorSelector($2) + $$, err = NewVectorSelector($2, $3) + if err != nil { yylex.Error(err.Error()); return 1 } } | IDENTIFIER '(' func_arg_list ')' { @@ -176,10 +187,10 @@ rule_expr : '(' rule_expr ')' $$, err = NewFunctionCall($1, []ast.Node{}) if err != nil { yylex.Error(err.Error()); return 1 } } - | rule_expr '[' DURATION ']' + | rule_expr '[' DURATION ']' offset_opts { var err error - $$, err = NewMatrixSelector($1, $3) + $$, err = NewMatrixSelector($1, $3, $5) if err != nil { yylex.Error(err.Error()); return 1 } } | AGGR_OP '(' rule_expr ')' grouping_opts extra_labels_opts diff --git a/rules/parser.y.go b/rules/parser.y.go index e70ab4b15..e69abcd6a 100644 --- a/rules/parser.y.go +++ b/rules/parser.y.go @@ -35,16 +35,17 @@ const NUMBER = 57352 const PERMANENT = 57353 const GROUP_OP = 57354 const KEEPING_EXTRA = 57355 -const AGGR_OP = 57356 -const CMP_OP = 57357 -const ADDITIVE_OP = 57358 -const MULT_OP = 57359 -const ALERT = 57360 -const IF = 57361 -const FOR = 57362 -const WITH = 57363 -const SUMMARY = 57364 -const DESCRIPTION = 57365 +const OFFSET = 57356 +const AGGR_OP = 57357 +const CMP_OP = 57358 +const ADDITIVE_OP = 57359 +const MULT_OP = 57360 +const ALERT = 57361 +const IF = 57362 +const FOR = 57363 +const WITH = 57364 +const SUMMARY = 57365 +const DESCRIPTION = 57366 var yyToknames = []string{ "START_RULES", @@ -57,6 +58,7 @@ var yyToknames = []string{ "PERMANENT", "GROUP_OP", "KEEPING_EXTRA", + "OFFSET", "AGGR_OP", "CMP_OP", "ADDITIVE_OP", @@ -75,7 +77,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyMaxDepth = 200 -//line parser.y:250 +//line parser.y:261 //line yacctab:1 var yyExca = []int{ @@ -87,91 +89,97 @@ var yyExca = []int{ -2, 10, } -const yyNprod = 50 +const yyNprod = 52 const yyPrivate = 57344 var yyTokenNames []string var yyStates []string -const yyLast = 137 +const yyLast = 142 var yyAct = []int{ - 56, 72, 50, 53, 30, 24, 6, 20, 49, 59, - 22, 10, 51, 18, 13, 12, 21, 19, 20, 11, - 18, 85, 36, 37, 38, 21, 19, 20, 81, 82, - 8, 18, 52, 7, 48, 66, 21, 19, 20, 87, - 18, 10, 51, 31, 13, 12, 60, 55, 28, 11, - 65, 18, 21, 19, 20, 57, 21, 19, 20, 29, - 8, 74, 23, 7, 62, 40, 39, 18, 73, 77, - 76, 18, 80, 75, 10, 19, 20, 13, 12, 79, - 86, 78, 11, 64, 89, 63, 41, 40, 71, 18, - 46, 25, 93, 8, 44, 27, 7, 83, 69, 96, - 94, 91, 58, 43, 9, 17, 54, 31, 92, 35, - 33, 45, 16, 13, 97, 95, 90, 61, 73, 88, - 32, 68, 25, 34, 2, 3, 14, 5, 4, 1, - 42, 84, 15, 26, 70, 67, 47, + 58, 76, 55, 52, 51, 30, 45, 6, 24, 20, + 61, 22, 10, 53, 18, 13, 12, 84, 68, 83, + 67, 11, 18, 36, 37, 38, 21, 19, 20, 21, + 19, 20, 8, 54, 90, 7, 50, 21, 19, 20, + 92, 18, 10, 53, 18, 13, 12, 70, 63, 62, + 88, 11, 18, 57, 31, 21, 19, 20, 86, 87, + 66, 40, 8, 10, 78, 7, 13, 12, 79, 69, + 18, 29, 11, 80, 82, 81, 28, 85, 21, 19, + 20, 19, 20, 8, 91, 77, 7, 41, 40, 94, + 25, 23, 39, 18, 59, 18, 44, 98, 27, 73, + 101, 99, 60, 96, 17, 43, 75, 9, 46, 56, + 31, 47, 16, 33, 97, 102, 13, 65, 35, 48, + 100, 95, 64, 32, 77, 93, 72, 25, 34, 2, + 3, 14, 5, 4, 1, 42, 89, 15, 26, 74, + 71, 49, } var yyPact = []int{ - 120, -1000, -1000, 68, 94, -1000, 41, 68, 116, 70, - 20, 31, -1000, -1000, -1000, 104, 117, -1000, 101, 68, - 68, 68, 37, 60, -1000, 79, -1000, 85, 5, 68, - 93, 19, 30, -1000, 83, -22, -10, -17, 59, -1000, - 116, -1000, 110, -1000, -1000, -1000, 38, 56, -1000, -1000, - 41, -1000, 21, 7, -1000, 115, 74, 62, 68, -1000, - -1000, -1000, -1000, -1000, 35, 95, 68, 52, -1000, 68, - 2, -1000, -1000, 73, 1, -1000, 93, 10, -1000, 113, - 41, -1000, 112, 109, 80, 100, -1000, -1000, -1000, -1000, - -1000, 30, -1000, 78, 108, 76, 107, -1000, + 125, -1000, -1000, 57, 93, -1000, 21, 57, 121, 72, + 47, 42, -1000, -1000, -1000, 107, 122, -1000, 110, 57, + 57, 57, 62, 60, -1000, 80, 94, 84, 6, 57, + 96, 24, 68, -1000, 82, -22, -9, -17, 64, -1000, + 121, 94, 115, -1000, -1000, -1000, 109, -1000, 33, -10, + -1000, -1000, 21, -1000, 39, 18, -1000, 120, 74, 79, + 57, 94, -1000, -1000, -1000, -1000, -1000, -1000, 36, 98, + 57, -11, -1000, 57, 31, -1000, -1000, 25, 13, -1000, + -1000, 96, 10, -1000, 119, 21, -1000, 118, 114, 81, + 106, -1000, -1000, -1000, -1000, -1000, 68, -1000, 78, 113, + 76, 108, -1000, } var yyPgo = []int{ - 0, 136, 135, 4, 1, 134, 0, 5, 62, 133, - 2, 8, 132, 3, 131, 104, 130, 129, 128, 127, - 126, + 0, 141, 140, 5, 1, 139, 0, 8, 91, 138, + 3, 4, 137, 2, 136, 107, 135, 6, 134, 133, + 132, 131, } var yyR1 = []int{ - 0, 17, 17, 18, 18, 19, 20, 20, 14, 14, + 0, 18, 18, 19, 19, 20, 21, 21, 14, 14, 12, 12, 15, 15, 6, 6, 6, 5, 5, 4, - 9, 9, 9, 8, 8, 7, 16, 16, 10, 10, + 9, 9, 9, 8, 8, 7, 16, 16, 17, 17, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 13, 13, 3, 3, 2, 2, 1, 1, 11, 11, + 10, 10, 13, 13, 3, 3, 2, 2, 1, 1, + 11, 11, } var yyR2 = []int{ 0, 2, 2, 0, 2, 1, 5, 11, 0, 2, 0, 1, 1, 1, 0, 3, 2, 1, 3, 3, - 0, 2, 3, 1, 3, 3, 1, 1, 3, 3, - 2, 4, 3, 4, 6, 6, 3, 3, 3, 1, - 0, 1, 0, 4, 1, 3, 1, 3, 1, 1, + 0, 2, 3, 1, 3, 3, 1, 1, 0, 2, + 3, 4, 3, 4, 3, 5, 6, 6, 3, 3, + 3, 1, 0, 1, 0, 4, 1, 3, 1, 3, + 1, 1, } var yyChk = []int{ - -1000, -17, 4, 5, -18, -19, -10, 28, 25, -15, - 6, 14, 10, 9, -20, -12, 18, 11, 30, 16, - 17, 15, -10, -8, -7, 6, -9, 25, 28, 28, - -3, 12, -15, 6, 6, 8, -10, -10, -10, 29, - 27, 26, -16, 24, 15, 26, -8, -1, 29, -11, - -10, 7, -10, -13, 13, 28, -6, 25, 19, 31, - -7, 7, 26, 29, 27, 29, 28, -2, 6, 24, - -5, 26, -4, 6, -10, -11, -3, -10, 29, 27, - -10, 26, 27, 24, -14, 20, -13, 29, 6, -4, - 7, 21, 8, -6, 22, 7, 23, 7, + -1000, -18, 4, 5, -19, -20, -10, 29, 26, -15, + 6, 15, 10, 9, -21, -12, 19, 11, 31, 17, + 18, 16, -10, -8, -7, 6, -9, 26, 29, 29, + -3, 12, -15, 6, 6, 8, -10, -10, -10, 30, + 28, 27, -16, 25, 16, -17, 14, 27, -8, -1, + 30, -11, -10, 7, -10, -13, 13, 29, -6, 26, + 20, 32, -7, -17, 7, 8, 27, 30, 28, 30, + 29, -2, 6, 25, -5, 27, -4, 6, -10, -17, + -11, -3, -10, 30, 28, -10, 27, 28, 25, -14, + 21, -13, 30, 6, -4, 7, 22, 8, -6, 23, + 7, 24, 7, } var yyDef = []int{ 0, -2, 3, 0, -2, 2, 5, 0, 0, 20, - 13, 42, 39, 12, 4, 0, 0, 11, 0, 0, - 0, 0, 0, 0, 23, 0, 30, 0, 0, 0, - 40, 0, 14, 13, 0, 0, 36, 37, 38, 28, - 0, 29, 0, 26, 27, 21, 0, 0, 32, 46, - 48, 49, 0, 0, 41, 0, 0, 0, 0, 33, - 24, 25, 22, 31, 0, 42, 0, 0, 44, 0, - 0, 16, 17, 0, 8, 47, 40, 0, 43, 0, - 6, 15, 0, 0, 0, 0, 34, 35, 45, 18, - 19, 14, 9, 0, 0, 0, 0, 7, + 13, 44, 41, 12, 4, 0, 0, 11, 0, 0, + 0, 0, 0, 0, 23, 0, 28, 0, 0, 0, + 42, 0, 14, 13, 0, 0, 38, 39, 40, 30, + 0, 28, 0, 26, 27, 32, 0, 21, 0, 0, + 34, 48, 50, 51, 0, 0, 43, 0, 0, 0, + 0, 28, 24, 31, 25, 29, 22, 33, 0, 44, + 0, 0, 46, 0, 0, 16, 17, 0, 8, 35, + 49, 42, 0, 45, 0, 6, 15, 0, 0, 0, + 0, 36, 37, 47, 18, 19, 14, 9, 0, 0, + 0, 0, 7, } var yyTok1 = []int{ @@ -179,21 +187,21 @@ var yyTok1 = []int{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 28, 29, 3, 3, 27, 3, 3, 3, 3, 3, + 29, 30, 3, 3, 28, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 24, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 30, 3, 31, 3, 3, 3, 3, 3, 3, + 3, 31, 3, 32, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 25, 3, 26, + 3, 3, 3, 26, 3, 27, } var yyTok2 = []int{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, + 22, 23, 24, } var yyTok3 = []int{ 0, @@ -559,27 +567,46 @@ yydefault: case 28: //line parser.y:156 { - yyVAL.ruleNode = yyS[yypt-1].ruleNode + yyVAL.str = "0s" } case 29: //line parser.y:158 { - yyVAL.ruleNode = ast.NewVectorSelector(yyS[yypt-1].labelMatchers) + yyVAL.str = yyS[yypt-0].str } case 30: - //line parser.y:160 + //line parser.y:162 + { + yyVAL.ruleNode = yyS[yypt-1].ruleNode + } + case 31: + //line parser.y:164 { var err error - m, err := metric.NewLabelMatcher(metric.Equal, clientmodel.MetricNameLabel, clientmodel.LabelValue(yyS[yypt-1].str)) + yyVAL.ruleNode, err = NewVectorSelector(yyS[yypt-2].labelMatchers, yyS[yypt-0].str) if err != nil { yylex.Error(err.Error()) return 1 } - yyS[yypt-0].labelMatchers = append(yyS[yypt-0].labelMatchers, m) - yyVAL.ruleNode = ast.NewVectorSelector(yyS[yypt-0].labelMatchers) } - case 31: - //line parser.y:168 + case 32: + //line parser.y:170 + { + var err error + m, err := metric.NewLabelMatcher(metric.Equal, clientmodel.MetricNameLabel, clientmodel.LabelValue(yyS[yypt-2].str)) + if err != nil { + yylex.Error(err.Error()) + return 1 + } + yyS[yypt-1].labelMatchers = append(yyS[yypt-1].labelMatchers, m) + yyVAL.ruleNode, err = NewVectorSelector(yyS[yypt-1].labelMatchers, yyS[yypt-0].str) + if err != nil { + yylex.Error(err.Error()) + return 1 + } + } + case 33: + //line parser.y:179 { var err error yyVAL.ruleNode, err = NewFunctionCall(yyS[yypt-3].str, yyS[yypt-1].ruleNodeSlice) @@ -588,8 +615,8 @@ yydefault: return 1 } } - case 32: - //line parser.y:174 + case 34: + //line parser.y:185 { var err error yyVAL.ruleNode, err = NewFunctionCall(yyS[yypt-2].str, []ast.Node{}) @@ -598,18 +625,18 @@ yydefault: return 1 } } - case 33: - //line parser.y:180 + case 35: + //line parser.y:191 { var err error - yyVAL.ruleNode, err = NewMatrixSelector(yyS[yypt-3].ruleNode, yyS[yypt-1].str) + yyVAL.ruleNode, err = NewMatrixSelector(yyS[yypt-4].ruleNode, yyS[yypt-2].str, yyS[yypt-0].str) if err != nil { yylex.Error(err.Error()) return 1 } } - case 34: - //line parser.y:186 + case 36: + //line parser.y:197 { var err error yyVAL.ruleNode, err = NewVectorAggregation(yyS[yypt-5].str, yyS[yypt-3].ruleNode, yyS[yypt-1].labelNameSlice, yyS[yypt-0].boolean) @@ -618,8 +645,8 @@ yydefault: return 1 } } - case 35: - //line parser.y:192 + case 37: + //line parser.y:203 { var err error yyVAL.ruleNode, err = NewVectorAggregation(yyS[yypt-5].str, yyS[yypt-1].ruleNode, yyS[yypt-4].labelNameSlice, yyS[yypt-3].boolean) @@ -628,28 +655,8 @@ yydefault: return 1 } } - case 36: - //line parser.y:200 - { - var err error - yyVAL.ruleNode, err = NewArithExpr(yyS[yypt-1].str, yyS[yypt-2].ruleNode, yyS[yypt-0].ruleNode) - if err != nil { - yylex.Error(err.Error()) - return 1 - } - } - case 37: - //line parser.y:206 - { - var err error - yyVAL.ruleNode, err = NewArithExpr(yyS[yypt-1].str, yyS[yypt-2].ruleNode, yyS[yypt-0].ruleNode) - if err != nil { - yylex.Error(err.Error()) - return 1 - } - } case 38: - //line parser.y:212 + //line parser.y:211 { var err error yyVAL.ruleNode, err = NewArithExpr(yyS[yypt-1].str, yyS[yypt-2].ruleNode, yyS[yypt-0].ruleNode) @@ -659,57 +666,77 @@ yydefault: } } case 39: - //line parser.y:218 + //line parser.y:217 + { + var err error + yyVAL.ruleNode, err = NewArithExpr(yyS[yypt-1].str, yyS[yypt-2].ruleNode, yyS[yypt-0].ruleNode) + if err != nil { + yylex.Error(err.Error()) + return 1 + } + } + case 40: + //line parser.y:223 + { + var err error + yyVAL.ruleNode, err = NewArithExpr(yyS[yypt-1].str, yyS[yypt-2].ruleNode, yyS[yypt-0].ruleNode) + if err != nil { + yylex.Error(err.Error()) + return 1 + } + } + case 41: + //line parser.y:229 { yyVAL.ruleNode = ast.NewScalarLiteral(yyS[yypt-0].num) } - case 40: - //line parser.y:222 + case 42: + //line parser.y:233 { yyVAL.boolean = false } - case 41: - //line parser.y:224 + case 43: + //line parser.y:235 { yyVAL.boolean = true } - case 42: - //line parser.y:228 + case 44: + //line parser.y:239 { yyVAL.labelNameSlice = clientmodel.LabelNames{} } - case 43: - //line parser.y:230 + case 45: + //line parser.y:241 { yyVAL.labelNameSlice = yyS[yypt-1].labelNameSlice } - case 44: - //line parser.y:234 + case 46: + //line parser.y:245 { yyVAL.labelNameSlice = clientmodel.LabelNames{clientmodel.LabelName(yyS[yypt-0].str)} } - case 45: - //line parser.y:236 + case 47: + //line parser.y:247 { yyVAL.labelNameSlice = append(yyVAL.labelNameSlice, clientmodel.LabelName(yyS[yypt-0].str)) } - case 46: - //line parser.y:240 + case 48: + //line parser.y:251 { yyVAL.ruleNodeSlice = []ast.Node{yyS[yypt-0].ruleNode} } - case 47: - //line parser.y:242 + case 49: + //line parser.y:253 { yyVAL.ruleNodeSlice = append(yyVAL.ruleNodeSlice, yyS[yypt-0].ruleNode) } - case 48: - //line parser.y:246 + case 50: + //line parser.y:257 { yyVAL.ruleNode = yyS[yypt-0].ruleNode } - case 49: - //line parser.y:248 + case 51: + //line parser.y:259 { yyVAL.ruleNode = ast.NewStringLiteral(yyS[yypt-0].str) } diff --git a/rules/rules_test.go b/rules/rules_test.go index 70ff6d843..2661e24ab 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -62,42 +62,32 @@ func newTestStorage(t testing.TB) (storage local.Storage, closer test.Closer) { func TestExpressions(t *testing.T) { // Labels in expected output need to be alphabetically sorted. expressionTests := []struct { - expr string - output []string - shouldFail bool - checkOrder bool - fullRanges int - intervalRanges int + expr string + output []string + shouldFail bool + checkOrder bool }{ { - expr: `SUM(http_requests)`, - output: []string{`{} => 3600 @[%v]`}, - fullRanges: 0, - intervalRanges: 8, + expr: `SUM(http_requests)`, + output: []string{`{} => 3600 @[%v]`}, }, { expr: `SUM(http_requests{instance="0"}) BY(job)`, output: []string{ `{job="api-server"} => 400 @[%v]`, `{job="app-server"} => 1200 @[%v]`, }, - fullRanges: 0, - intervalRanges: 4, }, { expr: `SUM(http_requests{instance="0"}) BY(job) KEEPING_EXTRA`, output: []string{ `{instance="0", job="api-server"} => 400 @[%v]`, `{instance="0", job="app-server"} => 1200 @[%v]`, }, - fullRanges: 0, - intervalRanges: 4, }, { expr: `SUM(http_requests) BY (job)`, output: []string{ `{job="api-server"} => 1000 @[%v]`, `{job="app-server"} => 2600 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { // Non-existent labels mentioned in BY-clauses shouldn't propagate to output. expr: `SUM(http_requests) BY (job, nonexistent)`, @@ -105,8 +95,6 @@ func TestExpressions(t *testing.T) { `{job="api-server"} => 1000 @[%v]`, `{job="app-server"} => 2600 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: ` // Test comment. @@ -116,16 +104,12 @@ func TestExpressions(t *testing.T) { `{job="api-server"} => 1000 @[%v]`, `{job="app-server"} => 2600 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `COUNT(http_requests) BY (job)`, output: []string{ `{job="api-server"} => 4 @[%v]`, `{job="app-server"} => 4 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job, group)`, output: []string{ @@ -134,139 +118,103 @@ func TestExpressions(t *testing.T) { `{group="production", job="api-server"} => 300 @[%v]`, `{group="production", job="app-server"} => 1100 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `AVG(http_requests) BY (job)`, output: []string{ `{job="api-server"} => 250 @[%v]`, `{job="app-server"} => 650 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `MIN(http_requests) BY (job)`, output: []string{ `{job="api-server"} => 100 @[%v]`, `{job="app-server"} => 500 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `MAX(http_requests) BY (job)`, output: []string{ `{job="api-server"} => 400 @[%v]`, `{job="app-server"} => 800 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) - COUNT(http_requests) BY (job)`, output: []string{ `{job="api-server"} => 996 @[%v]`, `{job="app-server"} => 2596 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `2 - SUM(http_requests) BY (job)`, output: []string{ `{job="api-server"} => -998 @[%v]`, `{job="app-server"} => -2598 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `1000 / SUM(http_requests) BY (job)`, output: []string{ `{job="api-server"} => 1 @[%v]`, `{job="app-server"} => 0.38461538461538464 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) - 2`, output: []string{ `{job="api-server"} => 998 @[%v]`, `{job="app-server"} => 2598 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) % 3`, output: []string{ `{job="api-server"} => 1 @[%v]`, `{job="app-server"} => 2 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) / 0`, output: []string{ `{job="api-server"} => +Inf @[%v]`, `{job="app-server"} => +Inf @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) > 1000`, output: []string{ `{job="app-server"} => 2600 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `1000 < SUM(http_requests) BY (job)`, output: []string{ `{job="app-server"} => 1000 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) <= 1000`, output: []string{ `{job="api-server"} => 1000 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) != 1000`, output: []string{ `{job="app-server"} => 2600 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) == 1000`, output: []string{ `{job="api-server"} => 1000 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `SUM(http_requests) BY (job) + SUM(http_requests) BY (job)`, output: []string{ `{job="api-server"} => 2000 @[%v]`, `{job="app-server"} => 5200 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `http_requests{job="api-server", group="canary"}`, output: []string{ `http_requests{group="canary", instance="0", job="api-server"} => 300 @[%v]`, `http_requests{group="canary", instance="1", job="api-server"} => 400 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `http_requests{job="api-server", group="canary"} + rate(http_requests{job="api-server"}[5m]) * 5 * 60`, output: []string{ `{group="canary", instance="0", job="api-server"} => 330 @[%v]`, `{group="canary", instance="1", job="api-server"} => 440 @[%v]`, }, - fullRanges: 4, - intervalRanges: 0, }, { expr: `rate(http_requests[25m]) * 25 * 60`, output: []string{ @@ -279,8 +227,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="1", job="api-server"} => 100 @[%v]`, `{group="production", instance="1", job="app-server"} => 300 @[%v]`, }, - fullRanges: 8, - intervalRanges: 0, }, { expr: `delta(http_requests[25m], 1)`, output: []string{ @@ -293,8 +239,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="1", job="api-server"} => 100 @[%v]`, `{group="production", instance="1", job="app-server"} => 300 @[%v]`, }, - fullRanges: 8, - intervalRanges: 0, }, { expr: `sort(http_requests)`, output: []string{ @@ -307,9 +251,7 @@ func TestExpressions(t *testing.T) { `http_requests{group="canary", instance="0", job="app-server"} => 700 @[%v]`, `http_requests{group="canary", instance="1", job="app-server"} => 800 @[%v]`, }, - checkOrder: true, - fullRanges: 0, - intervalRanges: 8, + checkOrder: true, }, { expr: `sort_desc(http_requests)`, output: []string{ @@ -322,9 +264,7 @@ func TestExpressions(t *testing.T) { `http_requests{group="production", instance="1", job="api-server"} => 200 @[%v]`, `http_requests{group="production", instance="0", job="api-server"} => 100 @[%v]`, }, - checkOrder: true, - fullRanges: 0, - intervalRanges: 8, + checkOrder: true, }, { expr: `topk(3, http_requests)`, output: []string{ @@ -332,18 +272,14 @@ func TestExpressions(t *testing.T) { `http_requests{group="canary", instance="0", job="app-server"} => 700 @[%v]`, `http_requests{group="production", instance="1", job="app-server"} => 600 @[%v]`, }, - checkOrder: true, - fullRanges: 0, - intervalRanges: 8, + checkOrder: true, }, { expr: `topk(5, http_requests{group="canary",job="app-server"})`, output: []string{ `http_requests{group="canary", instance="1", job="app-server"} => 800 @[%v]`, `http_requests{group="canary", instance="0", job="app-server"} => 700 @[%v]`, }, - checkOrder: true, - fullRanges: 0, - intervalRanges: 2, + checkOrder: true, }, { expr: `bottomk(3, http_requests)`, output: []string{ @@ -351,26 +287,20 @@ func TestExpressions(t *testing.T) { `http_requests{group="production", instance="1", job="api-server"} => 200 @[%v]`, `http_requests{group="canary", instance="0", job="api-server"} => 300 @[%v]`, }, - checkOrder: true, - fullRanges: 0, - intervalRanges: 8, + checkOrder: true, }, { expr: `bottomk(5, http_requests{group="canary",job="app-server"})`, output: []string{ `http_requests{group="canary", instance="0", job="app-server"} => 700 @[%v]`, `http_requests{group="canary", instance="1", job="app-server"} => 800 @[%v]`, }, - checkOrder: true, - fullRanges: 0, - intervalRanges: 2, + checkOrder: true, }, { // Single-letter label names and values. expr: `x{y="testvalue"}`, output: []string{ `x{y="testvalue"} => 100 @[%v]`, }, - fullRanges: 0, - intervalRanges: 1, }, { // Lower-cased aggregation operators should work too. expr: `sum(http_requests) by (job) + min(http_requests) by (job) + max(http_requests) by (job) + avg(http_requests) by (job)`, @@ -378,62 +308,42 @@ func TestExpressions(t *testing.T) { `{job="app-server"} => 4550 @[%v]`, `{job="api-server"} => 1750 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { // Deltas should be adjusted for target interval vs. samples under target interval. - expr: `delta(http_requests{group="canary", instance="1", job="app-server"}[18m])`, - output: []string{`{group="canary", instance="1", job="app-server"} => 288 @[%v]`}, - fullRanges: 1, - intervalRanges: 0, + expr: `delta(http_requests{group="canary", instance="1", job="app-server"}[18m])`, + output: []string{`{group="canary", instance="1", job="app-server"} => 288 @[%v]`}, }, { // Deltas should perform the same operation when 2nd argument is 0. - expr: `delta(http_requests{group="canary", instance="1", job="app-server"}[18m], 0)`, - output: []string{`{group="canary", instance="1", job="app-server"} => 288 @[%v]`}, - fullRanges: 1, - intervalRanges: 0, + expr: `delta(http_requests{group="canary", instance="1", job="app-server"}[18m], 0)`, + output: []string{`{group="canary", instance="1", job="app-server"} => 288 @[%v]`}, }, { // Rates should calculate per-second rates. - expr: `rate(http_requests{group="canary", instance="1", job="app-server"}[60m])`, - output: []string{`{group="canary", instance="1", job="app-server"} => 0.26666666666666666 @[%v]`}, - fullRanges: 1, - intervalRanges: 0, + expr: `rate(http_requests{group="canary", instance="1", job="app-server"}[60m])`, + output: []string{`{group="canary", instance="1", job="app-server"} => 0.26666666666666666 @[%v]`}, }, { // Deriv should return the same as rate in simple cases. - expr: `deriv(http_requests{group="canary", instance="1", job="app-server"}[60m])`, - output: []string{`{group="canary", instance="1", job="app-server"} => 0.26666666666666666 @[%v]`}, - fullRanges: 1, - intervalRanges: 0, + expr: `deriv(http_requests{group="canary", instance="1", job="app-server"}[60m])`, + output: []string{`{group="canary", instance="1", job="app-server"} => 0.26666666666666666 @[%v]`}, }, { // Counter resets at in the middle of range are handled correctly by rate(). - expr: `rate(testcounter_reset_middle[60m])`, - output: []string{`{} => 0.03 @[%v]`}, - fullRanges: 1, - intervalRanges: 0, + expr: `rate(testcounter_reset_middle[60m])`, + output: []string{`{} => 0.03 @[%v]`}, }, { // Counter resets at end of range are ignored by rate(). - expr: `rate(testcounter_reset_end[5m])`, - output: []string{`{} => 0 @[%v]`}, - fullRanges: 1, - intervalRanges: 0, + expr: `rate(testcounter_reset_end[5m])`, + output: []string{`{} => 0 @[%v]`}, }, { // Deriv should return correct result. - expr: `deriv(testcounter_reset_middle[100m])`, - output: []string{`{} => 0.010606060606060607 @[%v]`}, - fullRanges: 1, - intervalRanges: 0, + expr: `deriv(testcounter_reset_middle[100m])`, + output: []string{`{} => 0.010606060606060607 @[%v]`}, }, { // count_scalar for a non-empty vector should return scalar element count. - expr: `count_scalar(http_requests)`, - output: []string{`scalar: 8 @[%v]`}, - fullRanges: 0, - intervalRanges: 8, + expr: `count_scalar(http_requests)`, + output: []string{`scalar: 8 @[%v]`}, }, { // count_scalar for an empty vector should return scalar 0. - expr: `count_scalar(nonexistent)`, - output: []string{`scalar: 0 @[%v]`}, - fullRanges: 0, - intervalRanges: 0, + expr: `count_scalar(nonexistent)`, + output: []string{`scalar: 0 @[%v]`}, }, { // Empty expressions shouldn't parse. expr: ``, @@ -454,8 +364,6 @@ func TestExpressions(t *testing.T) { `http_requests{group="production", instance="1", job="api-server"} => 200 @[%v]`, `http_requests{group="production", instance="0", job="api-server"} => 100 @[%v]`, }, - fullRanges: 0, - intervalRanges: 4, }, { expr: `http_requests{job=~"server",group!="canary"}`, output: []string{ @@ -464,29 +372,21 @@ func TestExpressions(t *testing.T) { `http_requests{group="production", instance="1", job="api-server"} => 200 @[%v]`, `http_requests{group="production", instance="0", job="api-server"} => 100 @[%v]`, }, - fullRanges: 0, - intervalRanges: 4, }, { expr: `http_requests{job!~"api",group!="canary"}`, output: []string{ `http_requests{group="production", instance="1", job="app-server"} => 600 @[%v]`, `http_requests{group="production", instance="0", job="app-server"} => 500 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { - expr: `count_scalar(http_requests{job=~"^server$"})`, - output: []string{`scalar: 0 @[%v]`}, - fullRanges: 0, - intervalRanges: 0, + expr: `count_scalar(http_requests{job=~"^server$"})`, + output: []string{`scalar: 0 @[%v]`}, }, { expr: `http_requests{group="production",job=~"^api"}`, output: []string{ `http_requests{group="production", instance="0", job="api-server"} => 100 @[%v]`, `http_requests{group="production", instance="1", job="api-server"} => 200 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `abs(-1 * http_requests{group="production",job="api-server"})`, @@ -494,8 +394,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 100 @[%v]`, `{group="production", instance="1", job="api-server"} => 200 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `floor(0.004 * http_requests{group="production",job="api-server"})`, @@ -503,8 +401,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 0 @[%v]`, `{group="production", instance="1", job="api-server"} => 0 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `ceil(0.004 * http_requests{group="production",job="api-server"})`, @@ -512,8 +408,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 1 @[%v]`, `{group="production", instance="1", job="api-server"} => 1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `round(0.004 * http_requests{group="production",job="api-server"})`, @@ -521,8 +415,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 0 @[%v]`, `{group="production", instance="1", job="api-server"} => 1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { // Round should correctly handle negative numbers. expr: `round(-1 * (0.004 * http_requests{group="production",job="api-server"}))`, @@ -530,8 +422,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 0 @[%v]`, `{group="production", instance="1", job="api-server"} => -1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { // Round should round half up. expr: `round(0.005 * http_requests{group="production",job="api-server"})`, @@ -539,8 +429,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 1 @[%v]`, `{group="production", instance="1", job="api-server"} => 1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `round(-1 * (0.005 * http_requests{group="production",job="api-server"}))`, @@ -548,8 +436,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 0 @[%v]`, `{group="production", instance="1", job="api-server"} => -1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `round(1 + 0.005 * http_requests{group="production",job="api-server"})`, @@ -557,8 +443,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 2 @[%v]`, `{group="production", instance="1", job="api-server"} => 2 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `round(-1 * (1 + 0.005 * http_requests{group="production",job="api-server"}))`, @@ -566,8 +450,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => -1 @[%v]`, `{group="production", instance="1", job="api-server"} => -2 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { // Round should accept the number to round nearest to. expr: `round(0.0005 * http_requests{group="production",job="api-server"}, 0.1)`, @@ -575,8 +457,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 0.1 @[%v]`, `{group="production", instance="1", job="api-server"} => 0.1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `round(2.1 + 0.0005 * http_requests{group="production",job="api-server"}, 0.1)`, @@ -584,8 +464,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 2.2 @[%v]`, `{group="production", instance="1", job="api-server"} => 2.2 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `round(5.2 + 0.0005 * http_requests{group="production",job="api-server"}, 0.1)`, @@ -593,8 +471,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 5.3 @[%v]`, `{group="production", instance="1", job="api-server"} => 5.3 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { // Round should work correctly with negative numbers and multiple decimal places. expr: `round(-1 * (5.2 + 0.0005 * http_requests{group="production",job="api-server"}), 0.1)`, @@ -602,8 +478,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => -5.2 @[%v]`, `{group="production", instance="1", job="api-server"} => -5.3 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { // Round should work correctly with big toNearests. expr: `round(0.025 * http_requests{group="production",job="api-server"}, 5)`, @@ -611,8 +485,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 5 @[%v]`, `{group="production", instance="1", job="api-server"} => 5 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `round(0.045 * http_requests{group="production",job="api-server"}, 5)`, @@ -620,8 +492,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 5 @[%v]`, `{group="production", instance="1", job="api-server"} => 10 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `avg_over_time(http_requests{group="production",job="api-server"}[1h])`, @@ -629,8 +499,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 50 @[%v]`, `{group="production", instance="1", job="api-server"} => 100 @[%v]`, }, - fullRanges: 2, - intervalRanges: 0, }, { expr: `count_over_time(http_requests{group="production",job="api-server"}[1h])`, @@ -638,8 +506,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 11 @[%v]`, `{group="production", instance="1", job="api-server"} => 11 @[%v]`, }, - fullRanges: 2, - intervalRanges: 0, }, { expr: `max_over_time(http_requests{group="production",job="api-server"}[1h])`, @@ -647,8 +513,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 100 @[%v]`, `{group="production", instance="1", job="api-server"} => 200 @[%v]`, }, - fullRanges: 2, - intervalRanges: 0, }, { expr: `min_over_time(http_requests{group="production",job="api-server"}[1h])`, @@ -656,8 +520,6 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 0 @[%v]`, `{group="production", instance="1", job="api-server"} => 0 @[%v]`, }, - fullRanges: 2, - intervalRanges: 0, }, { expr: `sum_over_time(http_requests{group="production",job="api-server"}[1h])`, @@ -665,14 +527,10 @@ func TestExpressions(t *testing.T) { `{group="production", instance="0", job="api-server"} => 550 @[%v]`, `{group="production", instance="1", job="api-server"} => 1100 @[%v]`, }, - fullRanges: 2, - intervalRanges: 0, }, { - expr: `time()`, - output: []string{`scalar: 3000 @[%v]`}, - fullRanges: 0, - intervalRanges: 0, + expr: `time()`, + output: []string{`scalar: 3000 @[%v]`}, }, { expr: `drop_common_labels(http_requests{group="production",job="api-server"})`, @@ -680,8 +538,6 @@ func TestExpressions(t *testing.T) { `http_requests{instance="0"} => 100 @[%v]`, `http_requests{instance="1"} => 200 @[%v]`, }, - fullRanges: 0, - intervalRanges: 2, }, { expr: `{` + string(clientmodel.MetricNameLabel) + `=~".*"}`, @@ -698,8 +554,6 @@ func TestExpressions(t *testing.T) { `testcounter_reset_middle => 50 @[%v]`, `x{y="testvalue"} => 100 @[%v]`, }, - fullRanges: 0, - intervalRanges: 11, }, { expr: `{job=~"server", job!~"api"}`, @@ -709,8 +563,6 @@ func TestExpressions(t *testing.T) { `http_requests{group="production", instance="0", job="app-server"} => 500 @[%v]`, `http_requests{group="production", instance="1", job="app-server"} => 600 @[%v]`, }, - fullRanges: 0, - intervalRanges: 4, }, { // Test alternative "by"-clause order. @@ -719,8 +571,6 @@ func TestExpressions(t *testing.T) { `{group="canary"} => 700 @[%v]`, `{group="production"} => 300 @[%v]`, }, - fullRanges: 0, - intervalRanges: 4, }, { // Test alternative "by"-clause order with "keeping_extra". @@ -729,8 +579,6 @@ func TestExpressions(t *testing.T) { `{group="canary", job="api-server"} => 700 @[%v]`, `{group="production", job="api-server"} => 300 @[%v]`, }, - fullRanges: 0, - intervalRanges: 4, }, { // Test both alternative "by"-clause orders in one expression. @@ -740,48 +588,58 @@ func TestExpressions(t *testing.T) { output: []string{ `{job="api-server"} => 1000 @[%v]`, }, - fullRanges: 0, - intervalRanges: 4, }, { expr: `absent(nonexistent)`, output: []string{ `{} => 1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 0, }, { expr: `absent(nonexistent{job="testjob", instance="testinstance", method=~".*"})`, output: []string{ `{instance="testinstance", job="testjob"} => 1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 0, }, { expr: `count_scalar(absent(http_requests))`, output: []string{ `scalar: 0 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `count_scalar(absent(sum(http_requests)))`, output: []string{ `scalar: 0 @[%v]`, }, - fullRanges: 0, - intervalRanges: 8, }, { expr: `absent(sum(nonexistent{job="testjob", instance="testinstance"}))`, output: []string{ `{} => 1 @[%v]`, }, - fullRanges: 0, - intervalRanges: 0, + }, + { + expr: `http_requests{group="production",job="api-server"} offset 5m`, + output: []string{ + `http_requests{group="production", instance="0", job="api-server"} => 90 @[%v]`, + `http_requests{group="production", instance="1", job="api-server"} => 180 @[%v]`, + }, + }, + { + expr: `rate(http_requests{group="production",job="api-server"}[10m] offset 5m)`, + output: []string{ + `{group="production", instance="0", job="api-server"} => 0.03333333333333333 @[%v]`, + `{group="production", instance="1", job="api-server"} => 0.06666666666666667 @[%v]`, + }, + }, + { + expr: `rate(http_requests[10m]) offset 5m`, + shouldFail: true, + }, + { + expr: `sum(http_requests) offset 5m`, + shouldFail: true, }, } @@ -834,17 +692,6 @@ func TestExpressions(t *testing.T) { } } - analyzer := ast.NewQueryAnalyzer(storage) - ast.Walk(analyzer, testExpr) - if exprTest.fullRanges != len(analyzer.FullRanges) { - t.Errorf("%d. Count of full ranges didn't match: %v vs %v", i, exprTest.fullRanges, len(analyzer.FullRanges)) - failed = true - } - if exprTest.intervalRanges != len(analyzer.IntervalRanges) { - t.Errorf("%d. Count of interval ranges didn't match: %v vs %v", i, exprTest.intervalRanges, len(analyzer.IntervalRanges)) - failed = true - } - if failed { t.Errorf("%d. Expression: %v\n%v", i, exprTest.expr, vectorComparisonString(expectedLines, resultLines)) }