PromQL: export lexer (#6435)

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>
This commit is contained in:
Tobias Guggenmos 2019-12-09 19:03:31 +00:00 committed by Brian Brazil
parent 35c1f31721
commit 5c503d85f7
5 changed files with 301 additions and 301 deletions

View file

@ -21,7 +21,7 @@
%union { %union {
node Node node Node
item item item Item
matchers []*labels.Matcher matchers []*labels.Matcher
matcher *labels.Matcher matcher *labels.Matcher
} }
@ -148,7 +148,7 @@ match_op :
| EQL_REGEX {$$=$1} | EQL_REGEX {$$=$1}
| NEQ_REGEX {$$=$1} | NEQ_REGEX {$$=$1}
| error | error
{ yylex.(*parser).errorf("expected label matching operator but got %s", yylex.(*parser).token.val) } { yylex.(*parser).errorf("expected label matching operator but got %s", yylex.(*parser).token.Val) }
; ;

View file

@ -15,7 +15,7 @@ import (
type yySymType struct { type yySymType struct {
yys int yys int
node Node node Node
item item item Item
matchers []*labels.Matcher matchers []*labels.Matcher
matcher *labels.Matcher matcher *labels.Matcher
} }
@ -650,7 +650,7 @@ yydefault:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:151 //line promql/generated_parser.y:151
{ {
yylex.(*parser).errorf("expected label matching operator but got %s", yylex.(*parser).token.val) yylex.(*parser).errorf("expected label matching operator but got %s", yylex.(*parser).token.Val)
} }
} }
goto yystack /* stack new state and value */ goto yystack /* stack new state and value */

View file

@ -20,53 +20,53 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// item represents a token or text string returned from the scanner. // Item represents a token or text string returned from the scanner.
type item struct { type Item struct {
typ ItemType // The type of this item. Typ ItemType // The type of this Item.
pos Pos // The starting position, in bytes, of this item in the input string. Pos Pos // The starting position, in bytes, of this Item in the input string.
val string // The value of this item. Val string // The value of this Item.
} }
// String returns a descriptive string for the item. // String returns a descriptive string for the Item.
func (i item) String() string { func (i Item) String() string {
switch { switch {
case i.typ == EOF: case i.Typ == EOF:
return "EOF" return "EOF"
case i.typ == ERROR: case i.Typ == ERROR:
return i.val return i.Val
case i.typ == IDENTIFIER || i.typ == METRIC_IDENTIFIER: case i.Typ == IDENTIFIER || i.Typ == METRIC_IDENTIFIER:
return fmt.Sprintf("%q", i.val) return fmt.Sprintf("%q", i.Val)
case i.typ.isKeyword(): case i.Typ.isKeyword():
return fmt.Sprintf("<%s>", i.val) return fmt.Sprintf("<%s>", i.Val)
case i.typ.isOperator(): case i.Typ.isOperator():
return fmt.Sprintf("<op:%s>", i.val) return fmt.Sprintf("<op:%s>", i.Val)
case i.typ.isAggregator(): case i.Typ.isAggregator():
return fmt.Sprintf("<aggr:%s>", i.val) return fmt.Sprintf("<aggr:%s>", i.Val)
case len(i.val) > 10: case len(i.Val) > 10:
return fmt.Sprintf("%.10q...", i.val) return fmt.Sprintf("%.10q...", i.Val)
} }
return fmt.Sprintf("%q", i.val) return fmt.Sprintf("%q", i.Val)
} }
// isOperator returns true if the item corresponds to a arithmetic or set operator. // isOperator returns true if the Item corresponds to a arithmetic or set operator.
// Returns false otherwise. // Returns false otherwise.
func (i ItemType) isOperator() bool { return i > operatorsStart && i < operatorsEnd } func (i ItemType) isOperator() bool { return i > operatorsStart && i < operatorsEnd }
// isAggregator returns true if the item belongs to the aggregator functions. // isAggregator returns true if the Item belongs to the aggregator functions.
// Returns false otherwise // Returns false otherwise
func (i ItemType) isAggregator() bool { return i > aggregatorsStart && i < aggregatorsEnd } func (i ItemType) isAggregator() bool { return i > aggregatorsStart && i < aggregatorsEnd }
// isAggregator returns true if the item is an aggregator that takes a parameter. // isAggregator returns true if the Item is an aggregator that takes a parameter.
// Returns false otherwise // Returns false otherwise
func (i ItemType) isAggregatorWithParam() bool { func (i ItemType) isAggregatorWithParam() bool {
return i == TOPK || i == BOTTOMK || i == COUNT_VALUES || i == QUANTILE return i == TOPK || i == BOTTOMK || i == COUNT_VALUES || i == QUANTILE
} }
// isKeyword returns true if the item corresponds to a keyword. // isKeyword returns true if the Item corresponds to a keyword.
// Returns false otherwise. // Returns false otherwise.
func (i ItemType) isKeyword() bool { return i > keywordsStart && i < keywordsEnd } func (i ItemType) isKeyword() bool { return i > keywordsStart && i < keywordsEnd }
// isComparisonOperator returns true if the item corresponds to a comparison operator. // isComparisonOperator returns true if the Item corresponds to a comparison operator.
// Returns false otherwise. // Returns false otherwise.
func (i ItemType) isComparisonOperator() bool { func (i ItemType) isComparisonOperator() bool {
switch i { switch i {
@ -77,7 +77,7 @@ func (i ItemType) isComparisonOperator() bool {
} }
} }
// isSetOperator returns whether the item corresponds to a set operator. // isSetOperator returns whether the Item corresponds to a set operator.
func (i ItemType) isSetOperator() bool { func (i ItemType) isSetOperator() bool {
switch i { switch i {
case LAND, LOR, LUNLESS: case LAND, LOR, LUNLESS:
@ -153,9 +153,9 @@ var key = map[string]ItemType{
"bool": BOOL, "bool": BOOL,
} }
// These are the default string representations for common items. It does not // These are the default string representations for common Items. It does not
// imply that those are the only character sequences that can be lexed to such an item. // imply that those are the only character sequences that can be lexed to such an Item.
var itemTypeStr = map[ItemType]string{ var ItemTypeStr = map[ItemType]string{
LEFT_PAREN: "(", LEFT_PAREN: "(",
RIGHT_PAREN: ")", RIGHT_PAREN: ")",
LEFT_BRACE: "{", LEFT_BRACE: "{",
@ -187,9 +187,9 @@ var itemTypeStr = map[ItemType]string{
} }
func init() { func init() {
// Add keywords to item type strings. // Add keywords to Item type strings.
for s, ty := range key { for s, ty := range key {
itemTypeStr[ty] = s ItemTypeStr[ty] = s
} }
// Special numbers. // Special numbers.
key["inf"] = NUMBER key["inf"] = NUMBER
@ -197,20 +197,20 @@ func init() {
} }
func (i ItemType) String() string { func (i ItemType) String() string {
if s, ok := itemTypeStr[i]; ok { if s, ok := ItemTypeStr[i]; ok {
return s return s
} }
return fmt.Sprintf("<item %d>", i) return fmt.Sprintf("<Item %d>", i)
} }
func (i item) desc() string { func (i Item) desc() string {
if _, ok := itemTypeStr[i.typ]; ok { if _, ok := ItemTypeStr[i.Typ]; ok {
return i.String() return i.String()
} }
if i.typ == EOF { if i.Typ == EOF {
return i.typ.desc() return i.Typ.desc()
} }
return fmt.Sprintf("%s %s", i.typ.desc(), i) return fmt.Sprintf("%s %s", i.Typ.desc(), i)
} }
func (i ItemType) desc() string { func (i ItemType) desc() string {
@ -238,20 +238,20 @@ func (i ItemType) desc() string {
const eof = -1 const eof = -1
// stateFn represents the state of the scanner as a function that returns the next state. // stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn type stateFn func(*Lexer) stateFn
// Pos is the position in a string. // Pos is the position in a string.
type Pos int type Pos int
// lexer holds the state of the scanner. // Lexer holds the state of the scanner.
type lexer struct { type Lexer struct {
input string // The string being scanned. input string // The string being scanned.
state stateFn // The next lexing function to enter. state stateFn // The next lexing function to enter.
pos Pos // Current position in the input. pos Pos // Current position in the input.
start Pos // Start position of this item. start Pos // Start position of this Item.
width Pos // Width of last rune read from input. width Pos // Width of last rune read from input.
lastPos Pos // Position of most recent item returned by nextItem. lastPos Pos // Position of most recent Item returned by NextItem.
items []item // Slice buffer of scanned items. Items []Item // Slice buffer of scanned Items.
parenDepth int // Nesting depth of ( ) exprs. parenDepth int // Nesting depth of ( ) exprs.
braceOpen bool // Whether a { is opened. braceOpen bool // Whether a { is opened.
@ -265,7 +265,7 @@ type lexer struct {
} }
// next returns the next rune in the input. // next returns the next rune in the input.
func (l *lexer) next() rune { func (l *Lexer) next() rune {
if int(l.pos) >= len(l.input) { if int(l.pos) >= len(l.input) {
l.width = 0 l.width = 0
return eof return eof
@ -277,30 +277,30 @@ func (l *lexer) next() rune {
} }
// peek returns but does not consume the next rune in the input. // peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune { func (l *Lexer) peek() rune {
r := l.next() r := l.next()
l.backup() l.backup()
return r return r
} }
// backup steps back one rune. Can only be called once per call of next. // backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() { func (l *Lexer) backup() {
l.pos -= l.width l.pos -= l.width
} }
// emit passes an item back to the client. // emit passes an Item back to the client.
func (l *lexer) emit(t ItemType) { func (l *Lexer) emit(t ItemType) {
l.items = append(l.items, item{t, l.start, l.input[l.start:l.pos]}) l.Items = append(l.Items, Item{t, l.start, l.input[l.start:l.pos]})
l.start = l.pos l.start = l.pos
} }
// ignore skips over the pending input before this point. // ignore skips over the pending input before this point.
func (l *lexer) ignore() { func (l *Lexer) ignore() {
l.start = l.pos l.start = l.pos
} }
// accept consumes the next rune if it's from the valid set. // accept consumes the next rune if it's from the valid set.
func (l *lexer) accept(valid string) bool { func (l *Lexer) accept(valid string) bool {
if strings.ContainsRune(valid, l.next()) { if strings.ContainsRune(valid, l.next()) {
return true return true
} }
@ -309,7 +309,7 @@ func (l *lexer) accept(valid string) bool {
} }
// acceptRun consumes a run of runes from the valid set. // acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) { func (l *Lexer) acceptRun(valid string) {
for strings.ContainsRune(valid, l.next()) { for strings.ContainsRune(valid, l.next()) {
// consume // consume
} }
@ -317,15 +317,15 @@ func (l *lexer) acceptRun(valid string) {
} }
// lineNumber reports which line we're on, based on the position of // lineNumber reports which line we're on, based on the position of
// the previous item returned by nextItem. Doing it this way // the previous Item returned by NextItem. Doing it this way
// means we don't have to worry about peek double counting. // means we don't have to worry about peek double counting.
func (l *lexer) lineNumber() int { func (l *Lexer) lineNumber() int {
return 1 + strings.Count(l.input[:l.lastPos], "\n") return 1 + strings.Count(l.input[:l.lastPos], "\n")
} }
// linePosition reports at which character in the current line // linePosition reports at which character in the current line
// we are on. // we are on.
func (l *lexer) linePosition() int { func (l *Lexer) linePosition() int {
lb := strings.LastIndex(l.input[:l.lastPos], "\n") lb := strings.LastIndex(l.input[:l.lastPos], "\n")
if lb == -1 { if lb == -1 {
return 1 + int(l.lastPos) return 1 + int(l.lastPos)
@ -334,30 +334,30 @@ func (l *lexer) linePosition() int {
} }
// errorf returns an error token and terminates the scan by passing // errorf returns an error token and terminates the scan by passing
// back a nil pointer that will be the next state, terminating l.nextItem. // back a nil pointer that will be the next state, terminating l.NextItem.
func (l *lexer) errorf(format string, args ...interface{}) stateFn { func (l *Lexer) errorf(format string, args ...interface{}) stateFn {
l.items = append(l.items, item{ERROR, l.start, fmt.Sprintf(format, args...)}) l.Items = append(l.Items, Item{ERROR, l.start, fmt.Sprintf(format, args...)})
return nil return nil
} }
// nextItem returns the next item from the input. // NextItem returns the next Item from the input.
func (l *lexer) nextItem() item { func (l *Lexer) NextItem() Item {
for len(l.items) == 0 { for len(l.Items) == 0 {
if l.state != nil { if l.state != nil {
l.state = l.state(l) l.state = l.state(l)
} else { } else {
l.emit(EOF) l.emit(EOF)
} }
} }
item := l.items[0] Item := l.Items[0]
l.items = l.items[1:] l.Items = l.Items[1:]
l.lastPos = item.pos l.lastPos = Item.Pos
return item return Item
} }
// lex creates a new scanner for the input string. // lex creates a new scanner for the input string.
func lex(input string) *lexer { func Lex(input string) *Lexer {
l := &lexer{ l := &Lexer{
input: input, input: input,
state: lexStatements, state: lexStatements,
} }
@ -365,15 +365,15 @@ func lex(input string) *lexer {
} }
// run runs the state machine for the lexer. // run runs the state machine for the lexer.
func (l *lexer) run() { func (l *Lexer) run() {
for l.state = lexStatements; l.state != nil; { for l.state = lexStatements; l.state != nil; {
l.state = l.state(l) l.state = l.state(l)
} }
} }
// Release resources used by lexer. // Release resources used by lexer.
func (l *lexer) close() { func (l *Lexer) close() {
for range l.items { for range l.Items {
// Consume. // Consume.
} }
} }
@ -382,7 +382,7 @@ func (l *lexer) close() {
const lineComment = "#" const lineComment = "#"
// lexStatements is the top-level state for lexing. // lexStatements is the top-level state for lexing.
func lexStatements(l *lexer) stateFn { func lexStatements(l *Lexer) stateFn {
if l.braceOpen { if l.braceOpen {
return lexInsideBraces return lexInsideBraces
} }
@ -504,7 +504,7 @@ func lexStatements(l *lexer) stateFn {
// lexInsideBraces scans the inside of a vector selector. Keywords are ignored and // lexInsideBraces scans the inside of a vector selector. Keywords are ignored and
// scanned as identifiers. // scanned as identifiers.
func lexInsideBraces(l *lexer) stateFn { func lexInsideBraces(l *Lexer) stateFn {
if strings.HasPrefix(l.input[l.pos:], lineComment) { if strings.HasPrefix(l.input[l.pos:], lineComment) {
return lexLineComment return lexLineComment
} }
@ -558,7 +558,7 @@ func lexInsideBraces(l *lexer) stateFn {
} }
// lexValueSequence scans a value sequence of a series description. // lexValueSequence scans a value sequence of a series description.
func lexValueSequence(l *lexer) stateFn { func lexValueSequence(l *Lexer) stateFn {
switch r := l.next(); { switch r := l.next(); {
case r == eof: case r == eof:
return lexStatements return lexStatements
@ -578,7 +578,7 @@ func lexValueSequence(l *lexer) stateFn {
lexNumber(l) lexNumber(l)
case isAlpha(r): case isAlpha(r):
l.backup() l.backup()
// We might lex invalid items here but this will be caught by the parser. // We might lex invalid Items here but this will be caught by the parser.
return lexKeywordOrIdentifier return lexKeywordOrIdentifier
default: default:
return l.errorf("unexpected character in series sequence: %q", r) return l.errorf("unexpected character in series sequence: %q", r)
@ -594,7 +594,7 @@ func lexValueSequence(l *lexer) stateFn {
// package of the Go standard library to work for Prometheus-style strings. // package of the Go standard library to work for Prometheus-style strings.
// None of the actual escaping/quoting logic was changed in this function - it // None of the actual escaping/quoting logic was changed in this function - it
// was only modified to integrate with our lexer. // was only modified to integrate with our lexer.
func lexEscape(l *lexer) { func lexEscape(l *Lexer) {
var n int var n int
var base, max uint32 var base, max uint32
@ -653,7 +653,7 @@ func digitVal(ch rune) int {
} }
// skipSpaces skips the spaces until a non-space is encountered. // skipSpaces skips the spaces until a non-space is encountered.
func skipSpaces(l *lexer) { func skipSpaces(l *Lexer) {
for isSpace(l.peek()) { for isSpace(l.peek()) {
l.next() l.next()
} }
@ -661,7 +661,7 @@ func skipSpaces(l *lexer) {
} }
// lexString scans a quoted string. The initial quote has already been seen. // lexString scans a quoted string. The initial quote has already been seen.
func lexString(l *lexer) stateFn { func lexString(l *Lexer) stateFn {
Loop: Loop:
for { for {
switch l.next() { switch l.next() {
@ -680,7 +680,7 @@ Loop:
} }
// lexRawString scans a raw quoted string. The initial quote has already been seen. // lexRawString scans a raw quoted string. The initial quote has already been seen.
func lexRawString(l *lexer) stateFn { func lexRawString(l *Lexer) stateFn {
Loop: Loop:
for { for {
switch l.next() { switch l.next() {
@ -697,7 +697,7 @@ Loop:
} }
// lexSpace scans a run of space characters. One space has already been seen. // lexSpace scans a run of space characters. One space has already been seen.
func lexSpace(l *lexer) stateFn { func lexSpace(l *Lexer) stateFn {
for isSpace(l.peek()) { for isSpace(l.peek()) {
l.next() l.next()
} }
@ -706,7 +706,7 @@ func lexSpace(l *lexer) stateFn {
} }
// lexLineComment scans a line comment. Left comment marker is known to be present. // lexLineComment scans a line comment. Left comment marker is known to be present.
func lexLineComment(l *lexer) stateFn { func lexLineComment(l *Lexer) stateFn {
l.pos += Pos(len(lineComment)) l.pos += Pos(len(lineComment))
for r := l.next(); !isEndOfLine(r) && r != eof; { for r := l.next(); !isEndOfLine(r) && r != eof; {
r = l.next() r = l.next()
@ -716,7 +716,7 @@ func lexLineComment(l *lexer) stateFn {
return lexStatements return lexStatements
} }
func lexDuration(l *lexer) stateFn { func lexDuration(l *Lexer) stateFn {
if l.scanNumber() { if l.scanNumber() {
return l.errorf("missing unit character in duration") return l.errorf("missing unit character in duration")
} }
@ -733,7 +733,7 @@ func lexDuration(l *lexer) stateFn {
} }
// lexNumber scans a number: decimal, hex, oct or float. // lexNumber scans a number: decimal, hex, oct or float.
func lexNumber(l *lexer) stateFn { func lexNumber(l *Lexer) stateFn {
if !l.scanNumber() { if !l.scanNumber() {
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
} }
@ -741,8 +741,8 @@ func lexNumber(l *lexer) stateFn {
return lexStatements return lexStatements
} }
// lexNumberOrDuration scans a number or a duration item. // lexNumberOrDuration scans a number or a duration Item.
func lexNumberOrDuration(l *lexer) stateFn { func lexNumberOrDuration(l *Lexer) stateFn {
if l.scanNumber() { if l.scanNumber() {
l.emit(NUMBER) l.emit(NUMBER)
return lexStatements return lexStatements
@ -759,9 +759,9 @@ func lexNumberOrDuration(l *lexer) stateFn {
return l.errorf("bad number or duration syntax: %q", l.input[l.start:l.pos]) return l.errorf("bad number or duration syntax: %q", l.input[l.start:l.pos])
} }
// scanNumber scans numbers of different formats. The scanned item is // scanNumber scans numbers of different formats. The scanned Item is
// not necessarily a valid number. This case is caught by the parser. // not necessarily a valid number. This case is caught by the parser.
func (l *lexer) scanNumber() bool { func (l *Lexer) scanNumber() bool {
digits := "0123456789" digits := "0123456789"
// Disallow hexadecimal in series descriptions as the syntax is ambiguous. // Disallow hexadecimal in series descriptions as the syntax is ambiguous.
if !l.seriesDesc && l.accept("0") && l.accept("xX") { if !l.seriesDesc && l.accept("0") && l.accept("xX") {
@ -785,7 +785,7 @@ func (l *lexer) scanNumber() bool {
// lexIdentifier scans an alphanumeric identifier. The next character // lexIdentifier scans an alphanumeric identifier. The next character
// is known to be a letter. // is known to be a letter.
func lexIdentifier(l *lexer) stateFn { func lexIdentifier(l *Lexer) stateFn {
for isAlphaNumeric(l.next()) { for isAlphaNumeric(l.next()) {
// absorb // absorb
} }
@ -795,9 +795,9 @@ func lexIdentifier(l *lexer) stateFn {
} }
// lexKeywordOrIdentifier scans an alphanumeric identifier which may contain // lexKeywordOrIdentifier scans an alphanumeric identifier which may contain
// a colon rune. If the identifier is a keyword the respective keyword item // a colon rune. If the identifier is a keyword the respective keyword Item
// is scanned. // is scanned.
func lexKeywordOrIdentifier(l *lexer) stateFn { func lexKeywordOrIdentifier(l *Lexer) stateFn {
Loop: Loop:
for { for {
switch r := l.next(); { switch r := l.next(); {

View file

@ -21,7 +21,7 @@ import (
type testCase struct { type testCase struct {
input string input string
expected []item expected []Item
fail bool fail bool
seriesDesc bool // Whether to lex a series description. seriesDesc bool // Whether to lex a series description.
} }
@ -35,44 +35,44 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: ",", input: ",",
expected: []item{{COMMA, 0, ","}}, expected: []Item{{COMMA, 0, ","}},
}, { }, {
input: "()", input: "()",
expected: []item{{LEFT_PAREN, 0, `(`}, {RIGHT_PAREN, 1, `)`}}, expected: []Item{{LEFT_PAREN, 0, `(`}, {RIGHT_PAREN, 1, `)`}},
}, { }, {
input: "{}", input: "{}",
expected: []item{{LEFT_BRACE, 0, `{`}, {RIGHT_BRACE, 1, `}`}}, expected: []Item{{LEFT_BRACE, 0, `{`}, {RIGHT_BRACE, 1, `}`}},
}, { }, {
input: "[5m]", input: "[5m]",
expected: []item{ expected: []Item{
{LEFT_BRACKET, 0, `[`}, {LEFT_BRACKET, 0, `[`},
{DURATION, 1, `5m`}, {DURATION, 1, `5m`},
{RIGHT_BRACKET, 3, `]`}, {RIGHT_BRACKET, 3, `]`},
}, },
}, { }, {
input: "[ 5m]", input: "[ 5m]",
expected: []item{ expected: []Item{
{LEFT_BRACKET, 0, `[`}, {LEFT_BRACKET, 0, `[`},
{DURATION, 2, `5m`}, {DURATION, 2, `5m`},
{RIGHT_BRACKET, 4, `]`}, {RIGHT_BRACKET, 4, `]`},
}, },
}, { }, {
input: "[ 5m]", input: "[ 5m]",
expected: []item{ expected: []Item{
{LEFT_BRACKET, 0, `[`}, {LEFT_BRACKET, 0, `[`},
{DURATION, 3, `5m`}, {DURATION, 3, `5m`},
{RIGHT_BRACKET, 5, `]`}, {RIGHT_BRACKET, 5, `]`},
}, },
}, { }, {
input: "[ 5m ]", input: "[ 5m ]",
expected: []item{ expected: []Item{
{LEFT_BRACKET, 0, `[`}, {LEFT_BRACKET, 0, `[`},
{DURATION, 3, `5m`}, {DURATION, 3, `5m`},
{RIGHT_BRACKET, 6, `]`}, {RIGHT_BRACKET, 6, `]`},
}, },
}, { }, {
input: "\r\n\r", input: "\r\n\r",
expected: []item{}, expected: []Item{},
}, },
}, },
}, },
@ -81,55 +81,55 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: "1", input: "1",
expected: []item{{NUMBER, 0, "1"}}, expected: []Item{{NUMBER, 0, "1"}},
}, { }, {
input: "4.23", input: "4.23",
expected: []item{{NUMBER, 0, "4.23"}}, expected: []Item{{NUMBER, 0, "4.23"}},
}, { }, {
input: ".3", input: ".3",
expected: []item{{NUMBER, 0, ".3"}}, expected: []Item{{NUMBER, 0, ".3"}},
}, { }, {
input: "5.", input: "5.",
expected: []item{{NUMBER, 0, "5."}}, expected: []Item{{NUMBER, 0, "5."}},
}, { }, {
input: "NaN", input: "NaN",
expected: []item{{NUMBER, 0, "NaN"}}, expected: []Item{{NUMBER, 0, "NaN"}},
}, { }, {
input: "nAN", input: "nAN",
expected: []item{{NUMBER, 0, "nAN"}}, expected: []Item{{NUMBER, 0, "nAN"}},
}, { }, {
input: "NaN 123", input: "NaN 123",
expected: []item{{NUMBER, 0, "NaN"}, {NUMBER, 4, "123"}}, expected: []Item{{NUMBER, 0, "NaN"}, {NUMBER, 4, "123"}},
}, { }, {
input: "NaN123", input: "NaN123",
expected: []item{{IDENTIFIER, 0, "NaN123"}}, expected: []Item{{IDENTIFIER, 0, "NaN123"}},
}, { }, {
input: "iNf", input: "iNf",
expected: []item{{NUMBER, 0, "iNf"}}, expected: []Item{{NUMBER, 0, "iNf"}},
}, { }, {
input: "Inf", input: "Inf",
expected: []item{{NUMBER, 0, "Inf"}}, expected: []Item{{NUMBER, 0, "Inf"}},
}, { }, {
input: "+Inf", input: "+Inf",
expected: []item{{ADD, 0, "+"}, {NUMBER, 1, "Inf"}}, expected: []Item{{ADD, 0, "+"}, {NUMBER, 1, "Inf"}},
}, { }, {
input: "+Inf 123", input: "+Inf 123",
expected: []item{{ADD, 0, "+"}, {NUMBER, 1, "Inf"}, {NUMBER, 5, "123"}}, expected: []Item{{ADD, 0, "+"}, {NUMBER, 1, "Inf"}, {NUMBER, 5, "123"}},
}, { }, {
input: "-Inf", input: "-Inf",
expected: []item{{SUB, 0, "-"}, {NUMBER, 1, "Inf"}}, expected: []Item{{SUB, 0, "-"}, {NUMBER, 1, "Inf"}},
}, { }, {
input: "Infoo", input: "Infoo",
expected: []item{{IDENTIFIER, 0, "Infoo"}}, expected: []Item{{IDENTIFIER, 0, "Infoo"}},
}, { }, {
input: "-Infoo", input: "-Infoo",
expected: []item{{SUB, 0, "-"}, {IDENTIFIER, 1, "Infoo"}}, expected: []Item{{SUB, 0, "-"}, {IDENTIFIER, 1, "Infoo"}},
}, { }, {
input: "-Inf 123", input: "-Inf 123",
expected: []item{{SUB, 0, "-"}, {NUMBER, 1, "Inf"}, {NUMBER, 5, "123"}}, expected: []Item{{SUB, 0, "-"}, {NUMBER, 1, "Inf"}, {NUMBER, 5, "123"}},
}, { }, {
input: "0x123", input: "0x123",
expected: []item{{NUMBER, 0, "0x123"}}, expected: []Item{{NUMBER, 0, "0x123"}},
}, },
}, },
}, },
@ -138,22 +138,22 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: "\"test\\tsequence\"", input: "\"test\\tsequence\"",
expected: []item{{STRING, 0, `"test\tsequence"`}}, expected: []Item{{STRING, 0, `"test\tsequence"`}},
}, },
{ {
input: "\"test\\\\.expression\"", input: "\"test\\\\.expression\"",
expected: []item{{STRING, 0, `"test\\.expression"`}}, expected: []Item{{STRING, 0, `"test\\.expression"`}},
}, },
{ {
input: "\"test\\.expression\"", input: "\"test\\.expression\"",
expected: []item{ expected: []Item{
{ERROR, 0, "unknown escape sequence U+002E '.'"}, {ERROR, 0, "unknown escape sequence U+002E '.'"},
{STRING, 0, `"test\.expression"`}, {STRING, 0, `"test\.expression"`},
}, },
}, },
{ {
input: "`test\\.expression`", input: "`test\\.expression`",
expected: []item{{STRING, 0, "`test\\.expression`"}}, expected: []Item{{STRING, 0, "`test\\.expression`"}},
}, },
{ {
// See https://github.com/prometheus/prometheus/issues/939. // See https://github.com/prometheus/prometheus/issues/939.
@ -167,19 +167,19 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: "5s", input: "5s",
expected: []item{{DURATION, 0, "5s"}}, expected: []Item{{DURATION, 0, "5s"}},
}, { }, {
input: "123m", input: "123m",
expected: []item{{DURATION, 0, "123m"}}, expected: []Item{{DURATION, 0, "123m"}},
}, { }, {
input: "1h", input: "1h",
expected: []item{{DURATION, 0, "1h"}}, expected: []Item{{DURATION, 0, "1h"}},
}, { }, {
input: "3w", input: "3w",
expected: []item{{DURATION, 0, "3w"}}, expected: []Item{{DURATION, 0, "3w"}},
}, { }, {
input: "1y", input: "1y",
expected: []item{{DURATION, 0, "1y"}}, expected: []Item{{DURATION, 0, "1y"}},
}, },
}, },
}, },
@ -188,16 +188,16 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: "abc", input: "abc",
expected: []item{{IDENTIFIER, 0, "abc"}}, expected: []Item{{IDENTIFIER, 0, "abc"}},
}, { }, {
input: "a:bc", input: "a:bc",
expected: []item{{METRIC_IDENTIFIER, 0, "a:bc"}}, expected: []Item{{METRIC_IDENTIFIER, 0, "a:bc"}},
}, { }, {
input: "abc d", input: "abc d",
expected: []item{{IDENTIFIER, 0, "abc"}, {IDENTIFIER, 4, "d"}}, expected: []Item{{IDENTIFIER, 0, "abc"}, {IDENTIFIER, 4, "d"}},
}, { }, {
input: ":bc", input: ":bc",
expected: []item{{METRIC_IDENTIFIER, 0, ":bc"}}, expected: []Item{{METRIC_IDENTIFIER, 0, ":bc"}},
}, { }, {
input: "0a:bc", input: "0a:bc",
fail: true, fail: true,
@ -209,10 +209,10 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: "# some comment", input: "# some comment",
expected: []item{{COMMENT, 0, "# some comment"}}, expected: []Item{{COMMENT, 0, "# some comment"}},
}, { }, {
input: "5 # 1+1\n5", input: "5 # 1+1\n5",
expected: []item{ expected: []Item{
{NUMBER, 0, "5"}, {NUMBER, 0, "5"},
{COMMENT, 2, "# 1+1"}, {COMMENT, 2, "# 1+1"},
{NUMBER, 8, "5"}, {NUMBER, 8, "5"},
@ -225,56 +225,56 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: `=`, input: `=`,
expected: []item{{ASSIGN, 0, `=`}}, expected: []Item{{ASSIGN, 0, `=`}},
}, { }, {
// Inside braces equality is a single '=' character. // Inside braces equality is a single '=' character.
input: `{=}`, input: `{=}`,
expected: []item{{LEFT_BRACE, 0, `{`}, {EQL, 1, `=`}, {RIGHT_BRACE, 2, `}`}}, expected: []Item{{LEFT_BRACE, 0, `{`}, {EQL, 1, `=`}, {RIGHT_BRACE, 2, `}`}},
}, { }, {
input: `==`, input: `==`,
expected: []item{{EQL, 0, `==`}}, expected: []Item{{EQL, 0, `==`}},
}, { }, {
input: `!=`, input: `!=`,
expected: []item{{NEQ, 0, `!=`}}, expected: []Item{{NEQ, 0, `!=`}},
}, { }, {
input: `<`, input: `<`,
expected: []item{{LSS, 0, `<`}}, expected: []Item{{LSS, 0, `<`}},
}, { }, {
input: `>`, input: `>`,
expected: []item{{GTR, 0, `>`}}, expected: []Item{{GTR, 0, `>`}},
}, { }, {
input: `>=`, input: `>=`,
expected: []item{{GTE, 0, `>=`}}, expected: []Item{{GTE, 0, `>=`}},
}, { }, {
input: `<=`, input: `<=`,
expected: []item{{LTE, 0, `<=`}}, expected: []Item{{LTE, 0, `<=`}},
}, { }, {
input: `+`, input: `+`,
expected: []item{{ADD, 0, `+`}}, expected: []Item{{ADD, 0, `+`}},
}, { }, {
input: `-`, input: `-`,
expected: []item{{SUB, 0, `-`}}, expected: []Item{{SUB, 0, `-`}},
}, { }, {
input: `*`, input: `*`,
expected: []item{{MUL, 0, `*`}}, expected: []Item{{MUL, 0, `*`}},
}, { }, {
input: `/`, input: `/`,
expected: []item{{DIV, 0, `/`}}, expected: []Item{{DIV, 0, `/`}},
}, { }, {
input: `^`, input: `^`,
expected: []item{{POW, 0, `^`}}, expected: []Item{{POW, 0, `^`}},
}, { }, {
input: `%`, input: `%`,
expected: []item{{MOD, 0, `%`}}, expected: []Item{{MOD, 0, `%`}},
}, { }, {
input: `AND`, input: `AND`,
expected: []item{{LAND, 0, `AND`}}, expected: []Item{{LAND, 0, `AND`}},
}, { }, {
input: `or`, input: `or`,
expected: []item{{LOR, 0, `or`}}, expected: []Item{{LOR, 0, `or`}},
}, { }, {
input: `unless`, input: `unless`,
expected: []item{{LUNLESS, 0, `unless`}}, expected: []Item{{LUNLESS, 0, `unless`}},
}, },
}, },
}, },
@ -283,25 +283,25 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: `sum`, input: `sum`,
expected: []item{{SUM, 0, `sum`}}, expected: []Item{{SUM, 0, `sum`}},
}, { }, {
input: `AVG`, input: `AVG`,
expected: []item{{AVG, 0, `AVG`}}, expected: []Item{{AVG, 0, `AVG`}},
}, { }, {
input: `MAX`, input: `MAX`,
expected: []item{{MAX, 0, `MAX`}}, expected: []Item{{MAX, 0, `MAX`}},
}, { }, {
input: `min`, input: `min`,
expected: []item{{MIN, 0, `min`}}, expected: []Item{{MIN, 0, `min`}},
}, { }, {
input: `count`, input: `count`,
expected: []item{{COUNT, 0, `count`}}, expected: []Item{{COUNT, 0, `count`}},
}, { }, {
input: `stdvar`, input: `stdvar`,
expected: []item{{STDVAR, 0, `stdvar`}}, expected: []Item{{STDVAR, 0, `stdvar`}},
}, { }, {
input: `stddev`, input: `stddev`,
expected: []item{{STDDEV, 0, `stddev`}}, expected: []Item{{STDDEV, 0, `stddev`}},
}, },
}, },
}, },
@ -310,28 +310,28 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: "offset", input: "offset",
expected: []item{{OFFSET, 0, "offset"}}, expected: []Item{{OFFSET, 0, "offset"}},
}, { }, {
input: "by", input: "by",
expected: []item{{BY, 0, "by"}}, expected: []Item{{BY, 0, "by"}},
}, { }, {
input: "without", input: "without",
expected: []item{{WITHOUT, 0, "without"}}, expected: []Item{{WITHOUT, 0, "without"}},
}, { }, {
input: "on", input: "on",
expected: []item{{ON, 0, "on"}}, expected: []Item{{ON, 0, "on"}},
}, { }, {
input: "ignoring", input: "ignoring",
expected: []item{{IGNORING, 0, "ignoring"}}, expected: []Item{{IGNORING, 0, "ignoring"}},
}, { }, {
input: "group_left", input: "group_left",
expected: []item{{GROUP_LEFT, 0, "group_left"}}, expected: []Item{{GROUP_LEFT, 0, "group_left"}},
}, { }, {
input: "group_right", input: "group_right",
expected: []item{{GROUP_RIGHT, 0, "group_right"}}, expected: []Item{{GROUP_RIGHT, 0, "group_right"}},
}, { }, {
input: "bool", input: "bool",
expected: []item{{BOOL, 0, "bool"}}, expected: []Item{{BOOL, 0, "bool"}},
}, },
}, },
}, },
@ -349,7 +349,7 @@ var tests = []struct {
fail: true, fail: true,
}, { }, {
input: `{foo='bar'}`, input: `{foo='bar'}`,
expected: []item{ expected: []Item{
{LEFT_BRACE, 0, `{`}, {LEFT_BRACE, 0, `{`},
{IDENTIFIER, 1, `foo`}, {IDENTIFIER, 1, `foo`},
{EQL, 4, `=`}, {EQL, 4, `=`},
@ -358,7 +358,7 @@ var tests = []struct {
}, },
}, { }, {
input: `{foo="bar"}`, input: `{foo="bar"}`,
expected: []item{ expected: []Item{
{LEFT_BRACE, 0, `{`}, {LEFT_BRACE, 0, `{`},
{IDENTIFIER, 1, `foo`}, {IDENTIFIER, 1, `foo`},
{EQL, 4, `=`}, {EQL, 4, `=`},
@ -367,7 +367,7 @@ var tests = []struct {
}, },
}, { }, {
input: `{foo="bar\"bar"}`, input: `{foo="bar\"bar"}`,
expected: []item{ expected: []Item{
{LEFT_BRACE, 0, `{`}, {LEFT_BRACE, 0, `{`},
{IDENTIFIER, 1, `foo`}, {IDENTIFIER, 1, `foo`},
{EQL, 4, `=`}, {EQL, 4, `=`},
@ -376,7 +376,7 @@ var tests = []struct {
}, },
}, { }, {
input: `{NaN != "bar" }`, input: `{NaN != "bar" }`,
expected: []item{ expected: []Item{
{LEFT_BRACE, 0, `{`}, {LEFT_BRACE, 0, `{`},
{IDENTIFIER, 1, `NaN`}, {IDENTIFIER, 1, `NaN`},
{NEQ, 5, `!=`}, {NEQ, 5, `!=`},
@ -385,7 +385,7 @@ var tests = []struct {
}, },
}, { }, {
input: `{alert=~"bar" }`, input: `{alert=~"bar" }`,
expected: []item{ expected: []Item{
{LEFT_BRACE, 0, `{`}, {LEFT_BRACE, 0, `{`},
{IDENTIFIER, 1, `alert`}, {IDENTIFIER, 1, `alert`},
{EQL_REGEX, 6, `=~`}, {EQL_REGEX, 6, `=~`},
@ -394,7 +394,7 @@ var tests = []struct {
}, },
}, { }, {
input: `{on!~"bar"}`, input: `{on!~"bar"}`,
expected: []item{ expected: []Item{
{LEFT_BRACE, 0, `{`}, {LEFT_BRACE, 0, `{`},
{IDENTIFIER, 1, `on`}, {IDENTIFIER, 1, `on`},
{NEQ_REGEX, 3, `!~`}, {NEQ_REGEX, 3, `!~`},
@ -468,7 +468,7 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: `{} _ 1 x .3`, input: `{} _ 1 x .3`,
expected: []item{ expected: []Item{
{LEFT_BRACE, 0, `{`}, {LEFT_BRACE, 0, `{`},
{RIGHT_BRACE, 1, `}`}, {RIGHT_BRACE, 1, `}`},
{SPACE, 2, ` `}, {SPACE, 2, ` `},
@ -484,7 +484,7 @@ var tests = []struct {
}, },
{ {
input: `metric +Inf Inf NaN`, input: `metric +Inf Inf NaN`,
expected: []item{ expected: []Item{
{IDENTIFIER, 0, `metric`}, {IDENTIFIER, 0, `metric`},
{SPACE, 6, ` `}, {SPACE, 6, ` `},
{ADD, 7, `+`}, {ADD, 7, `+`},
@ -498,7 +498,7 @@ var tests = []struct {
}, },
{ {
input: `metric 1+1x4`, input: `metric 1+1x4`,
expected: []item{ expected: []Item{
{IDENTIFIER, 0, `metric`}, {IDENTIFIER, 0, `metric`},
{SPACE, 6, ` `}, {SPACE, 6, ` `},
{NUMBER, 7, `1`}, {NUMBER, 7, `1`},
@ -516,7 +516,7 @@ var tests = []struct {
tests: []testCase{ tests: []testCase{
{ {
input: `test_name{on!~"bar"}[4m:4s]`, input: `test_name{on!~"bar"}[4m:4s]`,
expected: []item{ expected: []Item{
{IDENTIFIER, 0, `test_name`}, {IDENTIFIER, 0, `test_name`},
{LEFT_BRACE, 9, `{`}, {LEFT_BRACE, 9, `{`},
{IDENTIFIER, 10, `on`}, {IDENTIFIER, 10, `on`},
@ -532,7 +532,7 @@ var tests = []struct {
}, },
{ {
input: `test:name{on!~"bar"}[4m:4s]`, input: `test:name{on!~"bar"}[4m:4s]`,
expected: []item{ expected: []Item{
{METRIC_IDENTIFIER, 0, `test:name`}, {METRIC_IDENTIFIER, 0, `test:name`},
{LEFT_BRACE, 9, `{`}, {LEFT_BRACE, 9, `{`},
{IDENTIFIER, 10, `on`}, {IDENTIFIER, 10, `on`},
@ -547,7 +547,7 @@ var tests = []struct {
}, },
}, { }, {
input: `test:name{on!~"b:ar"}[4m:4s]`, input: `test:name{on!~"b:ar"}[4m:4s]`,
expected: []item{ expected: []Item{
{METRIC_IDENTIFIER, 0, `test:name`}, {METRIC_IDENTIFIER, 0, `test:name`},
{LEFT_BRACE, 9, `{`}, {LEFT_BRACE, 9, `{`},
{IDENTIFIER, 10, `on`}, {IDENTIFIER, 10, `on`},
@ -562,7 +562,7 @@ var tests = []struct {
}, },
}, { }, {
input: `test:name{on!~"b:ar"}[4m:]`, input: `test:name{on!~"b:ar"}[4m:]`,
expected: []item{ expected: []Item{
{METRIC_IDENTIFIER, 0, `test:name`}, {METRIC_IDENTIFIER, 0, `test:name`},
{LEFT_BRACE, 9, `{`}, {LEFT_BRACE, 9, `{`},
{IDENTIFIER, 10, `on`}, {IDENTIFIER, 10, `on`},
@ -576,7 +576,7 @@ var tests = []struct {
}, },
}, { // Nested Subquery. }, { // Nested Subquery.
input: `min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s]`, input: `min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s]`,
expected: []item{ expected: []Item{
{IDENTIFIER, 0, `min_over_time`}, {IDENTIFIER, 0, `min_over_time`},
{LEFT_PAREN, 13, `(`}, {LEFT_PAREN, 13, `(`},
@ -607,7 +607,7 @@ var tests = []struct {
// Subquery with offset. // Subquery with offset.
{ {
input: `test:name{on!~"b:ar"}[4m:4s] offset 10m`, input: `test:name{on!~"b:ar"}[4m:4s] offset 10m`,
expected: []item{ expected: []Item{
{METRIC_IDENTIFIER, 0, `test:name`}, {METRIC_IDENTIFIER, 0, `test:name`},
{LEFT_BRACE, 9, `{`}, {LEFT_BRACE, 9, `{`},
{IDENTIFIER, 10, `on`}, {IDENTIFIER, 10, `on`},
@ -624,7 +624,7 @@ var tests = []struct {
}, },
}, { }, {
input: `min_over_time(rate(foo{bar="baz"}[2s])[5m:] offset 6m)[4m:3s]`, input: `min_over_time(rate(foo{bar="baz"}[2s])[5m:] offset 6m)[4m:3s]`,
expected: []item{ expected: []Item{
{IDENTIFIER, 0, `min_over_time`}, {IDENTIFIER, 0, `min_over_time`},
{LEFT_PAREN, 13, `(`}, {LEFT_PAREN, 13, `(`},
@ -656,7 +656,7 @@ var tests = []struct {
}, },
{ {
input: `test:name[ 5m]`, input: `test:name[ 5m]`,
expected: []item{ expected: []Item{
{METRIC_IDENTIFIER, 0, `test:name`}, {METRIC_IDENTIFIER, 0, `test:name`},
{LEFT_BRACKET, 9, `[`}, {LEFT_BRACKET, 9, `[`},
{DURATION, 11, `5m`}, {DURATION, 11, `5m`},
@ -693,28 +693,28 @@ func TestLexer(t *testing.T) {
for _, typ := range tests { for _, typ := range tests {
t.Run(typ.name, func(t *testing.T) { t.Run(typ.name, func(t *testing.T) {
for i, test := range typ.tests { for i, test := range typ.tests {
l := &lexer{ l := &Lexer{
input: test.input, input: test.input,
seriesDesc: test.seriesDesc, seriesDesc: test.seriesDesc,
} }
l.run() l.run()
out := l.items out := l.Items
lastItem := out[len(out)-1] lastItem := out[len(out)-1]
if test.fail { if test.fail {
if lastItem.typ != ERROR { if lastItem.Typ != ERROR {
t.Logf("%d: input %q", i, test.input) t.Logf("%d: input %q", i, test.input)
t.Fatalf("expected lexing error but did not fail") t.Fatalf("expected lexing error but did not fail")
} }
continue continue
} }
if lastItem.typ == ERROR { if lastItem.Typ == ERROR {
t.Logf("%d: input %q", i, test.input) t.Logf("%d: input %q", i, test.input)
t.Fatalf("unexpected lexing error at position %d: %s", lastItem.pos, lastItem) t.Fatalf("unexpected lexing error at position %d: %s", lastItem.Pos, lastItem)
} }
eofItem := item{EOF, Pos(len(test.input)), ""} eofItem := Item{EOF, Pos(len(test.input)), ""}
testutil.Equals(t, lastItem, eofItem, "%d: input %q", i, test.input) testutil.Equals(t, lastItem, eofItem, "%d: input %q", i, test.input)
out = out[:len(out)-1] out = out[:len(out)-1]

View file

@ -32,11 +32,11 @@ import (
) )
type parser struct { type parser struct {
lex *lexer lex *Lexer
token item token Item
peeking bool peeking bool
inject item inject Item
injecting bool injecting bool
switchSymbols []ItemType switchSymbols []ItemType
@ -74,7 +74,7 @@ func ParseMetric(input string) (m labels.Labels, err error) {
defer p.recover(&err) defer p.recover(&err)
m = p.metric() m = p.metric()
if p.peek().typ != EOF { if p.peek().Typ != EOF {
p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:]) p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
} }
return m, nil return m, nil
@ -87,11 +87,11 @@ func ParseMetricSelector(input string) (m []*labels.Matcher, err error) {
defer p.recover(&err) defer p.recover(&err)
name := "" name := ""
if t := p.peek().typ; t == METRIC_IDENTIFIER || t == IDENTIFIER { if t := p.peek().Typ; t == METRIC_IDENTIFIER || t == IDENTIFIER {
name = p.next().val name = p.next().Val
} }
vs := p.VectorSelector(name) vs := p.VectorSelector(name)
if p.peek().typ != EOF { if p.peek().Typ != EOF {
p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:]) p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
} }
return vs.LabelMatchers, nil return vs.LabelMatchers, nil
@ -100,7 +100,7 @@ func ParseMetricSelector(input string) (m []*labels.Matcher, err error) {
// newParser returns a new parser. // newParser returns a new parser.
func newParser(input string) *parser { func newParser(input string) *parser {
p := &parser{ p := &parser{
lex: lex(input), lex: Lex(input),
} }
return p return p
} }
@ -109,7 +109,7 @@ func newParser(input string) *parser {
func (p *parser) parseExpr() (expr Expr, err error) { func (p *parser) parseExpr() (expr Expr, err error) {
defer p.recover(&err) defer p.recover(&err)
for p.peek().typ != EOF { for p.peek().Typ != EOF {
if expr != nil { if expr != nil {
p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:]) p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
} }
@ -151,20 +151,20 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
const ctx = "series values" const ctx = "series values"
for { for {
for p.peek().typ == SPACE { for p.peek().Typ == SPACE {
p.next() p.next()
} }
if p.peek().typ == EOF { if p.peek().Typ == EOF {
break break
} }
// Extract blanks. // Extract blanks.
if p.peek().typ == BLANK { if p.peek().Typ == BLANK {
p.next() p.next()
times := uint64(1) times := uint64(1)
if p.peek().typ == TIMES { if p.peek().Typ == TIMES {
p.next() p.next()
times, err = strconv.ParseUint(p.expect(NUMBER, ctx).val, 10, 64) times, err = strconv.ParseUint(p.expect(NUMBER, ctx).Val, 10, 64)
if err != nil { if err != nil {
p.errorf("invalid repetition in %s: %s", ctx, err) p.errorf("invalid repetition in %s: %s", ctx, err)
} }
@ -174,7 +174,7 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
} }
// This is to ensure that there is a space between this and the next number. // 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. // This is especially required if the next number is negative.
if t := p.expectOneOf(SPACE, EOF, ctx).typ; t == EOF { if t := p.expectOneOf(SPACE, EOF, ctx).Typ; t == EOF {
break break
} }
continue continue
@ -182,15 +182,15 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
// Extract values. // Extract values.
sign := 1.0 sign := 1.0
if t := p.peek().typ; t == SUB || t == ADD { if t := p.peek().Typ; t == SUB || t == ADD {
if p.next().typ == SUB { if p.next().Typ == SUB {
sign = -1 sign = -1
} }
} }
var k float64 var k float64
if t := p.peek().typ; t == NUMBER { if t := p.peek().Typ; t == NUMBER {
k = sign * p.number(p.expect(NUMBER, ctx).val) k = sign * p.number(p.expect(NUMBER, ctx).Val)
} else if t == IDENTIFIER && p.peek().val == "stale" { } else if t == IDENTIFIER && p.peek().Val == "stale" {
p.next() p.next()
k = math.Float64frombits(value.StaleNaN) k = math.Float64frombits(value.StaleNaN)
} else { } else {
@ -201,24 +201,24 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
}) })
// If there are no offset repetitions specified, proceed with the next value. // If there are no offset repetitions specified, proceed with the next value.
if t := p.peek(); t.typ == SPACE { if t := p.peek(); t.Typ == SPACE {
// This ensures there is a space between every value. // This ensures there is a space between every value.
continue continue
} else if t.typ == EOF { } else if t.Typ == EOF {
break break
} else if t.typ != ADD && t.typ != SUB { } else if t.Typ != ADD && t.Typ != SUB {
p.errorf("expected next value or relative expansion in %s but got %s (value: %s)", ctx, t.desc(), p.peek()) 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. // Expand the repeated offsets into values.
sign = 1.0 sign = 1.0
if p.next().typ == SUB { if p.next().Typ == SUB {
sign = -1.0 sign = -1.0
} }
offset := sign * p.number(p.expect(NUMBER, ctx).val) offset := sign * p.number(p.expect(NUMBER, ctx).Val)
p.expect(TIMES, ctx) p.expect(TIMES, ctx)
times, err := strconv.ParseUint(p.expect(NUMBER, ctx).val, 10, 64) times, err := strconv.ParseUint(p.expect(NUMBER, ctx).Val, 10, 64)
if err != nil { if err != nil {
p.errorf("invalid repetition in %s: %s", ctx, err) p.errorf("invalid repetition in %s: %s", ctx, err)
} }
@ -232,7 +232,7 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
// This is to ensure that there is a space between this expanding notation // 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 // and the next number. This is especially required if the next number
// is negative. // is negative.
if t := p.expectOneOf(SPACE, EOF, ctx).typ; t == EOF { if t := p.expectOneOf(SPACE, EOF, ctx).Typ; t == EOF {
break break
} }
} }
@ -248,35 +248,35 @@ func (p *parser) typecheck(node Node) (err error) {
} }
// next returns the next token. // next returns the next token.
func (p *parser) next() item { func (p *parser) next() Item {
if !p.peeking { if !p.peeking {
t := p.lex.nextItem() t := p.lex.NextItem()
// Skip comments. // Skip comments.
for t.typ == COMMENT { for t.Typ == COMMENT {
t = p.lex.nextItem() t = p.lex.NextItem()
} }
p.token = t p.token = t
} }
p.peeking = false p.peeking = false
if p.token.typ == ERROR { if p.token.Typ == ERROR {
p.errorf("%s", p.token.val) p.errorf("%s", p.token.Val)
} }
return p.token return p.token
} }
// peek returns but does not consume the next token. // peek returns but does not consume the next token.
func (p *parser) peek() item { func (p *parser) peek() Item {
if p.peeking { if p.peeking {
return p.token return p.token
} }
p.peeking = true p.peeking = true
t := p.lex.nextItem() t := p.lex.NextItem()
// Skip comments. // Skip comments.
for t.typ == COMMENT { for t.Typ == COMMENT {
t = p.lex.nextItem() t = p.lex.NextItem()
} }
p.token = t p.token = t
return p.token return p.token
@ -306,18 +306,18 @@ func (p *parser) error(err error) {
} }
// expect consumes the next token and guarantees it has the required type. // expect consumes the next token and guarantees it has the required type.
func (p *parser) expect(exp ItemType, context string) item { func (p *parser) expect(exp ItemType, context string) Item {
token := p.next() token := p.next()
if token.typ != exp { if token.Typ != exp {
p.errorf("unexpected %s in %s, expected %s", token.desc(), context, exp.desc()) p.errorf("unexpected %s in %s, expected %s", token.desc(), context, exp.desc())
} }
return token return token
} }
// expectOneOf consumes the next token and guarantees it has one of the required types. // expectOneOf consumes the next token and guarantees it has one of the required types.
func (p *parser) expectOneOf(exp1, exp2 ItemType, context string) item { func (p *parser) expectOneOf(exp1, exp2 ItemType, context string) Item {
token := p.next() token := p.next()
if token.typ != exp1 && token.typ != exp2 { if token.Typ != exp1 && token.Typ != exp2 {
p.errorf("unexpected %s in %s, expected %s or %s", token.desc(), context, exp1.desc(), exp2.desc()) p.errorf("unexpected %s in %s, expected %s or %s", token.desc(), context, exp1.desc(), exp2.desc())
} }
return token return token
@ -342,7 +342,7 @@ func (p *parser) recover(errp *error) {
} }
// Lex is expected by the yyLexer interface of the yacc generated parser. // Lex is expected by the yyLexer interface of the yacc generated parser.
// It writes the next item provided by the lexer to the provided pointer address. // It writes the next Item provided by the lexer to the provided pointer address.
// Comments are skipped. // Comments are skipped.
// //
// The yyLexer interface is currently implemented by the parser to allow // The yyLexer interface is currently implemented by the parser to allow
@ -358,7 +358,7 @@ func (p *parser) Lex(lval *yySymType) int {
lval.item = p.next() lval.item = p.next()
} }
typ := lval.item.typ typ := lval.item.Typ
for _, t := range p.switchSymbols { for _, t := range p.switchSymbols {
if t == typ { if t == typ {
@ -377,23 +377,23 @@ func (p *parser) Lex(lval *yySymType) int {
func (p *parser) Error(e string) { func (p *parser) Error(e string) {
} }
// InjectItem allows injecting a single item at the beginning of the token stream // InjectItem allows injecting a single Item at the beginning of the token stream
// consumed by the generated parser. // consumed by the generated parser.
// This allows having multiple start symbols as described in // This allows having multiple start symbols as described in
// https://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html . // https://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html .
// Only the Lex function used by the generated parser is affected by this injected item. // Only the Lex function used by the generated parser is affected by this injected Item.
// Trying to inject when a previously injected item has not yet been consumed will panic. // Trying to inject when a previously injected Item has not yet been consumed will panic.
// Only item types that are supposed to be used as start symbols are allowed as an argument. // Only Item types that are supposed to be used as start symbols are allowed as an argument.
func (p *parser) InjectItem(typ ItemType) { func (p *parser) InjectItem(typ ItemType) {
if p.injecting { if p.injecting {
panic("cannot inject multiple items into the token stream") panic("cannot inject multiple Items into the token stream")
} }
if typ != 0 && (typ <= startSymbolsStart || typ >= startSymbolsEnd) { if typ != 0 && (typ <= startSymbolsStart || typ >= startSymbolsEnd) {
panic("cannot inject symbol that isn't start symbol") panic("cannot inject symbol that isn't start symbol")
} }
p.inject = item{typ: typ} p.inject = Item{Typ: typ}
p.injecting = true p.injecting = true
} }
@ -406,14 +406,14 @@ func (p *parser) expr() Expr {
// on the operators' precedence. // on the operators' precedence.
for { for {
// If the next token is not an operator the expression is done. // If the next token is not an operator the expression is done.
op := p.peek().typ op := p.peek().Typ
if !op.isOperator() { if !op.isOperator() {
// Check for subquery. // Check for subquery.
if op == LEFT_BRACKET { if op == LEFT_BRACKET {
expr = p.subqueryOrRangeSelector(expr, false) expr = p.subqueryOrRangeSelector(expr, false)
if s, ok := expr.(*SubqueryExpr); ok { if s, ok := expr.(*SubqueryExpr); ok {
// Parse optional offset. // Parse optional offset.
if p.peek().typ == OFFSET { if p.peek().Typ == OFFSET {
offset := p.offset() offset := p.offset()
s.Offset = offset s.Offset = offset
} }
@ -434,7 +434,7 @@ func (p *parser) expr() Expr {
returnBool := false returnBool := false
// Parse bool modifier. // Parse bool modifier.
if p.peek().typ == BOOL { if p.peek().Typ == BOOL {
if !op.isComparisonOperator() { if !op.isComparisonOperator() {
p.errorf("bool modifier can only be used on comparison operators") p.errorf("bool modifier can only be used on comparison operators")
} }
@ -443,22 +443,22 @@ func (p *parser) expr() Expr {
} }
// Parse ON/IGNORING clause. // Parse ON/IGNORING clause.
if p.peek().typ == ON || p.peek().typ == IGNORING { if p.peek().Typ == ON || p.peek().Typ == IGNORING {
if p.peek().typ == ON { if p.peek().Typ == ON {
vecMatching.On = true vecMatching.On = true
} }
p.next() p.next()
vecMatching.MatchingLabels = p.labels() vecMatching.MatchingLabels = p.labels()
// Parse grouping. // Parse grouping.
if t := p.peek().typ; t == GROUP_LEFT || t == GROUP_RIGHT { if t := p.peek().Typ; t == GROUP_LEFT || t == GROUP_RIGHT {
p.next() p.next()
if t == GROUP_LEFT { if t == GROUP_LEFT {
vecMatching.Card = CardManyToOne vecMatching.Card = CardManyToOne
} else { } else {
vecMatching.Card = CardOneToMany vecMatching.Card = CardOneToMany
} }
if p.peek().typ == LEFT_PAREN { if p.peek().Typ == LEFT_PAREN {
vecMatching.Include = p.labels() vecMatching.Include = p.labels()
} }
} }
@ -514,19 +514,19 @@ func (p *parser) balance(lhs Expr, op ItemType, rhs Expr, vecMatching *VectorMat
// <Vector_selector> | <Matrix_selector> | (+|-) <number_literal> | '(' <expr> ')' // <Vector_selector> | <Matrix_selector> | (+|-) <number_literal> | '(' <expr> ')'
// //
func (p *parser) unaryExpr() Expr { func (p *parser) unaryExpr() Expr {
switch t := p.peek(); t.typ { switch t := p.peek(); t.Typ {
case ADD, SUB: case ADD, SUB:
p.next() p.next()
e := p.unaryExpr() e := p.unaryExpr()
// Simplify unary expressions for number literals. // Simplify unary expressions for number literals.
if nl, ok := e.(*NumberLiteral); ok { if nl, ok := e.(*NumberLiteral); ok {
if t.typ == SUB { if t.Typ == SUB {
nl.Val *= -1 nl.Val *= -1
} }
return nl return nl
} }
return &UnaryExpr{Op: t.typ, Expr: e} return &UnaryExpr{Op: t.Typ, Expr: e}
case LEFT_PAREN: case LEFT_PAREN:
p.next() p.next()
@ -538,12 +538,12 @@ func (p *parser) unaryExpr() Expr {
e := p.primaryExpr() e := p.primaryExpr()
// Expression might be followed by a range selector. // Expression might be followed by a range selector.
if p.peek().typ == LEFT_BRACKET { if p.peek().Typ == LEFT_BRACKET {
e = p.subqueryOrRangeSelector(e, true) e = p.subqueryOrRangeSelector(e, true)
} }
// Parse optional offset. // Parse optional offset.
if p.peek().typ == OFFSET { if p.peek().Typ == OFFSET {
offset := p.offset() offset := p.offset()
switch s := e.(type) { switch s := e.(type) {
@ -577,16 +577,16 @@ func (p *parser) subqueryOrRangeSelector(expr Expr, checkRange bool) Expr {
var erange time.Duration var erange time.Duration
var err error var err error
erangeStr := p.expect(DURATION, ctx).val erangeStr := p.expect(DURATION, ctx).Val
erange, err = parseDuration(erangeStr) erange, err = parseDuration(erangeStr)
if err != nil { if err != nil {
p.error(err) p.error(err)
} }
var itm item var itm Item
if checkRange { if checkRange {
itm = p.expectOneOf(RIGHT_BRACKET, COLON, ctx) itm = p.expectOneOf(RIGHT_BRACKET, COLON, ctx)
if itm.typ == RIGHT_BRACKET { if itm.Typ == RIGHT_BRACKET {
// Range selector. // Range selector.
vs, ok := expr.(*VectorSelector) vs, ok := expr.(*VectorSelector)
if !ok { if !ok {
@ -606,8 +606,8 @@ func (p *parser) subqueryOrRangeSelector(expr Expr, checkRange bool) Expr {
var estep time.Duration var estep time.Duration
itm = p.expectOneOf(RIGHT_BRACKET, DURATION, ctx) itm = p.expectOneOf(RIGHT_BRACKET, DURATION, ctx)
if itm.typ == DURATION { if itm.Typ == DURATION {
estepStr := itm.val estepStr := itm.Val
estep, err = parseDuration(estepStr) estep, err = parseDuration(estepStr)
if err != nil { if err != nil {
p.error(err) p.error(err)
@ -641,29 +641,29 @@ func (p *parser) number(val string) float64 {
// //
func (p *parser) primaryExpr() Expr { func (p *parser) primaryExpr() Expr {
switch t := p.next(); { switch t := p.next(); {
case t.typ == NUMBER: case t.Typ == NUMBER:
f := p.number(t.val) f := p.number(t.Val)
return &NumberLiteral{f} return &NumberLiteral{f}
case t.typ == STRING: case t.Typ == STRING:
return &StringLiteral{p.unquoteString(t.val)} return &StringLiteral{p.unquoteString(t.Val)}
case t.typ == LEFT_BRACE: case t.Typ == LEFT_BRACE:
// Metric selector without metric name. // Metric selector without metric name.
p.backup() p.backup()
return p.VectorSelector("") return p.VectorSelector("")
case t.typ == IDENTIFIER: case t.Typ == IDENTIFIER:
// Check for function call. // Check for function call.
if p.peek().typ == LEFT_PAREN { if p.peek().Typ == LEFT_PAREN {
return p.call(t.val) return p.call(t.Val)
} }
fallthrough // Else metric selector. fallthrough // Else metric selector.
case t.typ == METRIC_IDENTIFIER: case t.Typ == METRIC_IDENTIFIER:
return p.VectorSelector(t.val) return p.VectorSelector(t.Val)
case t.typ.isAggregator(): case t.Typ.isAggregator():
p.backup() p.backup()
return p.aggrExpr() return p.aggrExpr()
@ -683,15 +683,15 @@ func (p *parser) labels() []string {
p.expect(LEFT_PAREN, ctx) p.expect(LEFT_PAREN, ctx)
labels := []string{} labels := []string{}
if p.peek().typ != RIGHT_PAREN { if p.peek().Typ != RIGHT_PAREN {
for { for {
id := p.next() id := p.next()
if !isLabel(id.val) { if !isLabel(id.Val) {
p.errorf("unexpected %s in %s, expected label", id.desc(), ctx) p.errorf("unexpected %s in %s, expected label", id.desc(), ctx)
} }
labels = append(labels, id.val) labels = append(labels, id.Val)
if p.peek().typ != COMMA { if p.peek().Typ != COMMA {
break break
} }
p.next() p.next()
@ -711,7 +711,7 @@ func (p *parser) aggrExpr() *AggregateExpr {
const ctx = "aggregation" const ctx = "aggregation"
agop := p.next() agop := p.next()
if !agop.typ.isAggregator() { if !agop.Typ.isAggregator() {
p.errorf("expected aggregation operator but got %s", agop) p.errorf("expected aggregation operator but got %s", agop)
} }
var grouping []string var grouping []string
@ -719,7 +719,7 @@ func (p *parser) aggrExpr() *AggregateExpr {
modifiersFirst := false modifiersFirst := false
if t := p.peek().typ; t == BY || t == WITHOUT { if t := p.peek().Typ; t == BY || t == WITHOUT {
if t == WITHOUT { if t == WITHOUT {
without = true without = true
} }
@ -730,7 +730,7 @@ func (p *parser) aggrExpr() *AggregateExpr {
p.expect(LEFT_PAREN, ctx) p.expect(LEFT_PAREN, ctx)
var param Expr var param Expr
if agop.typ.isAggregatorWithParam() { if agop.Typ.isAggregatorWithParam() {
param = p.expr() param = p.expr()
p.expect(COMMA, ctx) p.expect(COMMA, ctx)
} }
@ -738,7 +738,7 @@ func (p *parser) aggrExpr() *AggregateExpr {
p.expect(RIGHT_PAREN, ctx) p.expect(RIGHT_PAREN, ctx)
if !modifiersFirst { if !modifiersFirst {
if t := p.peek().typ; t == BY || t == WITHOUT { if t := p.peek().Typ; t == BY || t == WITHOUT {
if len(grouping) > 0 { if len(grouping) > 0 {
p.errorf("aggregation must only contain one grouping clause") p.errorf("aggregation must only contain one grouping clause")
} }
@ -751,7 +751,7 @@ func (p *parser) aggrExpr() *AggregateExpr {
} }
return &AggregateExpr{ return &AggregateExpr{
Op: agop.typ, Op: agop.Typ,
Expr: e, Expr: e,
Param: param, Param: param,
Grouping: grouping, Grouping: grouping,
@ -773,7 +773,7 @@ func (p *parser) call(name string) *Call {
p.expect(LEFT_PAREN, ctx) p.expect(LEFT_PAREN, ctx)
// Might be call without args. // Might be call without args.
if p.peek().typ == RIGHT_PAREN { if p.peek().Typ == RIGHT_PAREN {
p.next() // Consume. p.next() // Consume.
return &Call{fn, nil} return &Call{fn, nil}
} }
@ -784,7 +784,7 @@ func (p *parser) call(name string) *Call {
args = append(args, e) args = append(args, e)
// Terminate if no more arguments. // Terminate if no more arguments.
if p.peek().typ != COMMA { if p.peek().Typ != COMMA {
break break
} }
p.next() p.next()
@ -820,7 +820,7 @@ func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
p.expect(LEFT_BRACE, ctx) p.expect(LEFT_BRACE, ctx)
// Check if no matchers are provided. // Check if no matchers are provided.
if p.peek().typ == RIGHT_BRACE { if p.peek().Typ == RIGHT_BRACE {
p.next() p.next()
return matchers return matchers
} }
@ -828,7 +828,7 @@ func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
for { for {
label := p.expect(IDENTIFIER, ctx) label := p.expect(IDENTIFIER, ctx)
op := p.next().typ op := p.next().Typ
if !op.isOperator() { if !op.isOperator() {
p.errorf("expected label matching operator but got %s", op) p.errorf("expected label matching operator but got %s", op)
} }
@ -842,9 +842,9 @@ func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
p.errorf("operator must be one of %q, is %q", operators, op) p.errorf("operator must be one of %q, is %q", operators, op)
} }
val := p.unquoteString(p.expect(STRING, ctx).val) val := p.unquoteString(p.expect(STRING, ctx).Val)
// Map the item to the respective match type. // Map the Item to the respective match type.
var matchType labels.MatchType var matchType labels.MatchType
switch op { switch op {
case EQL: case EQL:
@ -856,28 +856,28 @@ func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
case NEQ_REGEX: case NEQ_REGEX:
matchType = labels.MatchNotRegexp matchType = labels.MatchNotRegexp
default: default:
p.errorf("item %q is not a metric match type", op) p.errorf("Item %q is not a metric match type", op)
} }
m, err := labels.NewMatcher(matchType, label.val, val) m, err := labels.NewMatcher(matchType, label.Val, val)
if err != nil { if err != nil {
p.error(err) p.error(err)
} }
matchers = append(matchers, m) matchers = append(matchers, m)
if p.peek().typ == IDENTIFIER { if p.peek().Typ == IDENTIFIER {
p.errorf("missing comma before next identifier %q", p.peek().val) p.errorf("missing comma before next identifier %q", p.peek().Val)
} }
// Terminate list if last matcher. // Terminate list if last matcher.
if p.peek().typ != COMMA { if p.peek().Typ != COMMA {
break break
} }
p.next() p.next()
// Allow comma after each item in a multi-line listing. // Allow comma after each Item in a multi-line listing.
if p.peek().typ == RIGHT_BRACE { if p.peek().Typ == RIGHT_BRACE {
break break
} }
} }
@ -896,10 +896,10 @@ func (p *parser) metric() labels.Labels {
name := "" name := ""
var m labels.Labels var m labels.Labels
t := p.peek().typ t := p.peek().Typ
if t == IDENTIFIER || t == METRIC_IDENTIFIER { if t == IDENTIFIER || t == METRIC_IDENTIFIER {
name = p.next().val name = p.next().Val
t = p.peek().typ t = p.peek().Typ
} }
if t != LEFT_BRACE && name == "" { if t != LEFT_BRACE && name == "" {
p.errorf("missing metric name or metric selector") p.errorf("missing metric name or metric selector")
@ -924,7 +924,7 @@ func (p *parser) offset() time.Duration {
p.next() p.next()
offi := p.expect(DURATION, ctx) offi := p.expect(DURATION, ctx)
offset, err := parseDuration(offi.val) offset, err := parseDuration(offi.Val)
if err != nil { if err != nil {
p.error(err) p.error(err)
} }
@ -942,7 +942,7 @@ func (p *parser) VectorSelector(name string) *VectorSelector {
Name: name, Name: name,
} }
// Parse label matching if any. // Parse label matching if any.
if t := p.peek(); t.typ == LEFT_BRACE { if t := p.peek(); t.Typ == LEFT_BRACE {
p.generatedParserResult = ret p.generatedParserResult = ret
p.parseGenerated(START_LABELS, []ItemType{RIGHT_BRACE, EOF}) p.parseGenerated(START_LABELS, []ItemType{RIGHT_BRACE, EOF})
@ -1152,11 +1152,11 @@ func (p *parser) parseGenerated(startSymbol ItemType, switchSymbols []ItemType)
} }
func (p *parser) newLabelMatcher(label item, operator item, value item) *labels.Matcher { func (p *parser) newLabelMatcher(label Item, operator Item, value Item) *labels.Matcher {
op := operator.typ op := operator.Typ
val := p.unquoteString(value.val) val := p.unquoteString(value.Val)
// Map the item to the respective match type. // Map the Item to the respective match type.
var matchType labels.MatchType var matchType labels.MatchType
switch op { switch op {
case EQL: case EQL:
@ -1173,7 +1173,7 @@ func (p *parser) newLabelMatcher(label item, operator item, value item) *labels.
panic("invalid operator") panic("invalid operator")
} }
m, err := labels.NewMatcher(matchType, label.val, val) m, err := labels.NewMatcher(matchType, label.Val, val)
if err != nil { if err != nil {
p.error(err) p.error(err)
} }