promql: Allow injecting fake tokens into the generated parser (#6381)

* promql: Allow injecting fake tokens into the generated parser

Yacc grammars do not support having multiple start symbols.

To work around that restriction, it is possible to inject fake tokens into the lexer stream,
as described here https://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html .

This is part of the parser rewrite effort described in #6256.

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>
pull/6384/head
Tobias Guggenmos 5 years ago committed by Brian Brazil
parent fa1489e35c
commit 408574a6e1

@ -193,6 +193,10 @@ const (
GROUP_RIGHT GROUP_RIGHT
BOOL BOOL
keywordsEnd keywordsEnd
startSymbolsStart
// Start symbols for the generated parser.
startSymbolsEnd
) )
var key = map[string]ItemType{ var key = map[string]ItemType{

@ -35,6 +35,9 @@ type parser struct {
lex *lexer lex *lexer
token item token item
peeking bool peeking bool
inject item
injecting bool
} }
// ParseErr wraps a parsing error with line and position context. // ParseErr wraps a parsing error with line and position context.
@ -352,7 +355,12 @@ type yySymType item
// //
// For more information, see https://godoc.org/golang.org/x/tools/cmd/goyacc. // For more information, see https://godoc.org/golang.org/x/tools/cmd/goyacc.
func (p *parser) Lex(lval *yySymType) int { func (p *parser) Lex(lval *yySymType) int {
*lval = yySymType(p.next()) if p.injecting {
*lval = yySymType(p.inject)
p.injecting = false
} else {
*lval = yySymType(p.next())
}
return int(item(*lval).typ) return int(item(*lval).typ)
} }
@ -364,6 +372,26 @@ func (p *parser) Error(e string) {
p.errorf(e) p.errorf(e)
} }
// InjectItem allows injecting a single item at the beginning of the token stream
// consumed by the generated parser.
// This allows having multiple start symbols as described in
// 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.
// 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.
func (p *parser) InjectItem(typ ItemType) {
if p.injecting {
panic("cannot inject multiple items into the token stream")
}
if typ <= startSymbolsStart || typ >= startSymbolsEnd {
panic("cannot inject symbol that isn't start symbol")
}
p.inject = item{typ: typ}
p.injecting = true
}
// expr parses any expression. // expr parses any expression.
func (p *parser) expr() Expr { func (p *parser) expr() Expr {
// Parse the starting expression. // Parse the starting expression.

Loading…
Cancel
Save