Files
hetty/pkg/filter/parser.go

251 lines
4.8 KiB
Go
Raw Normal View History

package filter
2020-11-16 22:14:58 +01:00
import (
"fmt"
2022-01-21 11:45:54 +01:00
"regexp"
2020-11-16 22:14:58 +01:00
)
type precedence int
const (
_ precedence = iota
precLowest
precAnd
precOr
precNot
precEq
2020-11-16 22:14:58 +01:00
precLessGreater
precPrefix
precGroup
)
2021-04-25 16:23:53 +02:00
type (
prefixParser func(*Parser) (Expression, error)
infixParser func(*Parser, Expression) (Expression, error)
)
2020-11-16 22:14:58 +01:00
var (
prefixParsers = map[TokenType]prefixParser{}
infixParsers = map[TokenType]infixParser{}
)
var tokenPrecedences = map[TokenType]precedence{
TokParenOpen: precGroup,
TokOpNot: precNot,
TokOpAnd: precAnd,
TokOpOr: precOr,
TokOpEq: precEq,
TokOpNotEq: precEq,
TokOpGt: precLessGreater,
TokOpLt: precLessGreater,
TokOpGtEq: precLessGreater,
TokOpLtEq: precLessGreater,
TokOpRe: precEq,
TokOpNotRe: precEq,
}
func init() {
// Populate maps in `init`, because package global variables would cause an
// initialization cycle.
infixOperators := []TokenType{
TokOpAnd,
TokOpOr,
TokOpEq,
TokOpNotEq,
TokOpGt,
TokOpLt,
TokOpGtEq,
TokOpLtEq,
TokOpRe,
TokOpNotRe,
}
for _, op := range infixOperators {
infixParsers[op] = parseInfixExpression
}
prefixParsers[TokOpNot] = parsePrefixExpression
prefixParsers[TokString] = parseStringLiteral
prefixParsers[TokParenOpen] = parseGroupedExpression
}
type Parser struct {
l *Lexer
cur Token
peek Token
}
func NewParser(l *Lexer) *Parser {
p := &Parser{l: l}
p.nextToken()
p.nextToken()
return p
}
func ParseQuery(input string) (expr Expression, err error) {
p := &Parser{l: NewLexer(input)}
p.nextToken()
p.nextToken()
if p.curTokenIs(TokEOF) {
return nil, fmt.Errorf("filter: unexpected EOF")
2020-11-16 22:14:58 +01:00
}
for !p.curTokenIs(TokEOF) {
right, err := p.parseExpression(precLowest)
2021-04-25 16:23:53 +02:00
switch {
case err != nil:
return nil, fmt.Errorf("filter: could not parse expression: %w", err)
2021-04-25 16:23:53 +02:00
case expr == nil:
2020-11-16 22:14:58 +01:00
expr = right
2021-04-25 16:23:53 +02:00
default:
2022-01-21 11:45:54 +01:00
expr = InfixExpression{
2020-11-16 22:14:58 +01:00
Operator: TokOpAnd,
Left: expr,
Right: right,
}
}
2021-04-25 16:23:53 +02:00
2020-11-16 22:14:58 +01:00
p.nextToken()
}
return
}
func (p *Parser) nextToken() {
p.cur = p.peek
p.peek = p.l.Next()
}
func (p *Parser) curTokenIs(t TokenType) bool {
return p.cur.Type == t
}
func (p *Parser) peekTokenIs(t TokenType) bool {
return p.peek.Type == t
}
func (p *Parser) curPrecedence() precedence {
if p, ok := tokenPrecedences[p.cur.Type]; ok {
return p
}
2021-04-25 16:23:53 +02:00
2020-11-16 22:14:58 +01:00
return precLowest
}
func (p *Parser) peekPrecedence() precedence {
if p, ok := tokenPrecedences[p.peek.Type]; ok {
return p
}
2021-04-25 16:23:53 +02:00
2020-11-16 22:14:58 +01:00
return precLowest
}
func (p *Parser) parseExpression(prec precedence) (Expression, error) {
prefixParser, ok := prefixParsers[p.cur.Type]
if !ok {
return nil, fmt.Errorf("no prefix parse function for %v found", p.cur.Type)
}
expr, err := prefixParser(p)
if err != nil {
2021-04-25 16:23:53 +02:00
return nil, fmt.Errorf("could not parse expression prefix: %w", err)
2020-11-16 22:14:58 +01:00
}
for !p.peekTokenIs(eof) && prec < p.peekPrecedence() {
infixParser, ok := infixParsers[p.peek.Type]
if !ok {
break
}
p.nextToken()
expr, err = infixParser(p, expr)
if err != nil {
2021-04-25 16:23:53 +02:00
return nil, fmt.Errorf("could not parse infix expression: %w", err)
2020-11-16 22:14:58 +01:00
}
}
return expr, nil
}
func parsePrefixExpression(p *Parser) (Expression, error) {
2022-01-21 11:45:54 +01:00
expr := PrefixExpression{
2020-11-16 22:14:58 +01:00
Operator: p.cur.Type,
}
p.nextToken()
right, err := p.parseExpression(precPrefix)
if err != nil {
2021-04-25 16:23:53 +02:00
return nil, fmt.Errorf("could not parse expression for right operand: %w", err)
2020-11-16 22:14:58 +01:00
}
2021-04-25 16:23:53 +02:00
2020-11-16 22:14:58 +01:00
expr.Right = right
return expr, nil
}
func parseInfixExpression(p *Parser, left Expression) (Expression, error) {
2022-01-21 11:45:54 +01:00
expr := InfixExpression{
2020-11-16 22:14:58 +01:00
Operator: p.cur.Type,
Left: left,
}
prec := p.curPrecedence()
p.nextToken()
right, err := p.parseExpression(prec)
if err != nil {
2021-04-25 16:23:53 +02:00
return nil, fmt.Errorf("could not parse expression for right operand: %w", err)
2020-11-16 22:14:58 +01:00
}
2021-04-25 16:23:53 +02:00
2022-01-21 11:45:54 +01:00
if expr.Operator == TokOpRe || expr.Operator == TokOpNotRe {
if rightStr, ok := right.(StringLiteral); ok {
re, err := regexp.Compile(rightStr.Value)
if err != nil {
return nil, fmt.Errorf("could not compile regular expression %q: %w", rightStr.Value, err)
}
2022-03-23 14:31:27 +01:00
right = RegexpLiteral{re}
2022-01-21 11:45:54 +01:00
}
}
2020-11-16 22:14:58 +01:00
expr.Right = right
return expr, nil
}
func parseStringLiteral(p *Parser) (Expression, error) {
2022-01-21 11:45:54 +01:00
return StringLiteral{Value: p.cur.Literal}, nil
2020-11-16 22:14:58 +01:00
}
func parseGroupedExpression(p *Parser) (Expression, error) {
p.nextToken()
expr, err := p.parseExpression(precLowest)
if err != nil {
2021-04-25 16:23:53 +02:00
return nil, fmt.Errorf("could not parse grouped expression: %w", err)
2020-11-16 22:14:58 +01:00
}
for p.nextToken(); !p.curTokenIs(TokParenClose); p.nextToken() {
if p.curTokenIs(TokEOF) {
return nil, fmt.Errorf("unexpected EOF: unmatched parentheses")
}
2021-04-25 16:23:53 +02:00
right, err := p.parseExpression(precLowest)
if err != nil {
2021-04-25 16:23:53 +02:00
return nil, fmt.Errorf("could not parse expression: %w", err)
}
2021-04-25 16:23:53 +02:00
2022-01-21 11:45:54 +01:00
expr = InfixExpression{
Operator: TokOpAnd,
Left: expr,
Right: right,
}
2020-11-16 22:14:58 +01:00
}
return expr, nil
}