promql/parse.go
func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err error) {
	defer p.recover(&err)

	m = p.metric()

	const ctx = "series values"
	for {
		for p.peek().typ == ItemSpace {
			p.next()
		}
		if p.peek().typ == ItemEOF {
			break
		}

		// Extract blanks.
		if p.peek().typ == ItemBlank {
			p.next()
			times := uint64(1)
			if p.peek().typ == ItemTimes {
				p.next()
				times, err = strconv.ParseUint(p.expect(ItemNumber, ctx).val, 10, 64)
				if err != nil {
					p.errorf("invalid repetition in %s: %s", ctx, err)
				}
			}
			for i := uint64(0); i < times; i++ {
				vals = append(vals, sequenceValue{omitted: true})
			}
			// This is to ensure that there is a space between this and the next number.
			// This is especially required if the next number is negative.
			if t := p.expectOneOf(ItemSpace, ItemEOF, ctx).typ; t == ItemEOF {
				break
			}
			continue
		}

		// Extract values.
		sign := 1.0
		if t := p.peek().typ; t == ItemSUB || t == ItemADD {
			if p.next().typ == ItemSUB {
				sign = -1
			}
		}
		var k float64
		if t := p.peek().typ; t == ItemNumber {
			k = sign * p.number(p.expect(ItemNumber, ctx).val)
		} else if t == ItemIdentifier && p.peek().val == "stale" {
			p.next()
			k = math.Float64frombits(value.StaleNaN)
		} else {
			p.errorf("expected number or 'stale' in %s but got %s (value: %s)", ctx, t.desc(), p.peek())
		}
		vals = append(vals, sequenceValue{
			value: k,
		})

		// If there are no offset repetitions specified, proceed with the next value.
		if t := p.peek(); t.typ == ItemSpace {
			// This ensures there is a space between every value.
			continue
		} else if t.typ == ItemEOF {
			break
		} else if t.typ != ItemADD && t.typ != ItemSUB {
			p.errorf("expected next value or relative expansion in %s but got %s (value: %s)", ctx, t.desc(), p.peek())
		}

		// Expand the repeated offsets into values.
		sign = 1.0
		if p.next().typ == ItemSUB {
			sign = -1.0
		}
		offset := sign * p.number(p.expect(ItemNumber, ctx).val)
		p.expect(ItemTimes, ctx)

		times, err := strconv.ParseUint(p.expect(ItemNumber, ctx).val, 10, 64)
		if err != nil {
			p.errorf("invalid repetition in %s: %s", ctx, err)
		}

		for i := uint64(0); i < times; i++ {
			k += offset
			vals = append(vals, sequenceValue{
				value: k,
			})
		}
		// This is to ensure that there is a space between this expanding notation
		// and the next number. This is especially required if the next number
		// is negative.
		if t := p.expectOneOf(ItemSpace, ItemEOF, ctx).typ; t == ItemEOF {
			break
		}
	}
	return m, vals, nil
}
func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err error) {
	defer p.recover(&err)

	m = p.metric()

	const ctx = "series values"
	for {
		for p.peek().typ == ItemSpace {
			p.next()
		}
		if p.peek().typ == ItemEOF {
			break
		}

		// Extract blanks.
		if p.peek().typ == ItemBlank {
			p.next()
			times := uint64(1)
			if p.peek().typ == ItemTimes {
				p.next()
				times, err = strconv.ParseUint(p.expect(ItemNumber, ctx).val, 10, 64)
				if err != nil {
					p.errorf("invalid repetition in %s: %s", ctx, err)
				}
			}
			for i := uint64(0); i < times; i++ {
				vals = append(vals, sequenceValue{omitted: true})
			}
			// This is to ensure that there is a space between this and the next number.
			// This is especially required if the next number is negative.
			if t := p.expectOneOf(ItemSpace, ItemEOF, ctx).typ; t == ItemEOF {
				break
			}
			continue
		}

		// Extract values.
		sign := 1.0
		if t := p.peek().typ; t == ItemSUB || t == ItemADD {
			if p.next().typ == ItemSUB {
				sign = -1
			}
		}
		var k float64
		if t := p.peek().typ; t == ItemNumber {
			k = sign * p.number(p.expect(ItemNumber, ctx).val)
		} else if t == ItemIdentifier && p.peek().val == "stale" {
			p.next()
			k = math.Float64frombits(value.StaleNaN)
		} else {
			p.errorf("expected number or 'stale' in %s but got %s (value: %s)", ctx, t.desc(), p.peek())
		}
		vals = append(vals, sequenceValue{
			value: k,
		})

		// If there are no offset repetitions specified, proceed with the next value.
		if t := p.peek(); t.typ == ItemSpace {
			// This ensures there is a space between every value.
			continue
		} else if t.typ == ItemEOF {
			break
		} else if t.typ != ItemADD && t.typ != ItemSUB {
			p.errorf("expected next value or relative expansion in %s but got %s (value: %s)", ctx, t.desc(), p.peek())
		}

		// Expand the repeated offsets into values.
		sign = 1.0
		if p.next().typ == ItemSUB {
			sign = -1.0
		}
		offset := sign * p.number(p.expect(ItemNumber, ctx).val)
		p.expect(ItemTimes, ctx)

		times, err := strconv.ParseUint(p.expect(ItemNumber, ctx).val, 10, 64)
		if err != nil {
			p.errorf("invalid repetition in %s: %s", ctx, err)
		}

		for i := uint64(0); i < times; i++ {
			k += offset
			vals = append(vals, sequenceValue{
				value: k,
			})
		}
		// This is to ensure that there is a space between this expanding notation
		// and the next number. This is especially required if the next number
		// is negative.
		if t := p.expectOneOf(ItemSpace, ItemEOF, ctx).typ; t == ItemEOF {
			break
		}
	}
	return m, vals, nil
}
// parseSeriesDesc parses a description of a time series into its metric and value sequence.