{ package bexpr import ( "strconv" "strings" ) } Input <- _? "(" _? expr:OrExpression _? ")" _? EOF { return expr, nil } / _? expr:OrExpression _? EOF { return expr, nil } OrExpression <- left:AndExpression _ "or" _ right:OrExpression { return &BinaryExpression{ Operator: BinaryOpOr, Left: left.(Expression), Right: right.(Expression), }, nil } / expr:AndExpression { return expr, nil } AndExpression <- left:NotExpression _ "and" _ right:AndExpression { return &BinaryExpression{ Operator: BinaryOpAnd, Left: left.(Expression), Right: right.(Expression), }, nil } / expr:NotExpression { return expr, nil } NotExpression <- "not" _ expr:NotExpression { if unary, ok := expr.(*UnaryExpression); ok && unary.Operator == UnaryOpNot { // small optimization to get rid unnecessary levels of AST nodes // for things like: not not foo == 3 which is equivalent to foo == 3 return unary.Operand, nil } return &UnaryExpression{ Operator: UnaryOpNot, Operand: expr.(Expression), }, nil } / expr:ParenthesizedExpression { return expr, nil } ParenthesizedExpression "grouping" <- "(" _? expr:OrExpression _? ")" { return expr, nil } / expr:MatchExpression { return expr, nil } / "(" _? OrExpression _? !")" &{ return false, errors.New("Unmatched parentheses") } MatchExpression "match" <- MatchSelectorOpValue / MatchSelectorOp / MatchValueOpSelector MatchSelectorOpValue "match" <- selector:Selector operator:(MatchEqual / MatchNotEqual / MatchContains / MatchNotContains / MatchMatches / MatchNotMatches) value:Value { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: value.(*MatchValue)}, nil } MatchSelectorOp "match" <- selector:Selector operator:(MatchIsEmpty / MatchIsNotEmpty) { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: nil}, nil } MatchValueOpSelector "match" <- value:Value operator:(MatchIn / MatchNotIn) selector:Selector { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: value.(*MatchValue)}, nil } / Value operator:(MatchIn / MatchNotIn) !Selector &{ return false, errors.New("Invalid selector") } MatchEqual <- _? "==" _? { return MatchEqual, nil } MatchNotEqual <- _? "!=" _? { return MatchNotEqual, nil } MatchIsEmpty <- _ "is" _ "empty" { return MatchIsEmpty, nil } MatchIsNotEmpty <- _"is" _ "not" _ "empty" { return MatchIsNotEmpty, nil } MatchIn <- _ "in" _ { return MatchIn, nil } MatchNotIn <- _ "not" _ "in" _ { return MatchNotIn, nil } MatchContains <- _ "contains" _ { return MatchIn, nil } MatchNotContains <- _ "not" _ "contains" _ { return MatchNotIn, nil } MatchMatches <- _ "matches" _ { return MatchMatches, nil } MatchNotMatches <- _ "not" _ "matches" _ { return MatchNotMatches, nil } Selector "selector" <- first:Identifier rest:SelectorOrIndex* { sel := Selector{ first.(string), } if rest != nil { for _, v := range rest.([]interface{}) { sel = append(sel, v.(string)) } } return sel, nil } Identifier <- [a-zA-Z] [a-zA-Z0-9_]* { return string(c.text), nil } SelectorOrIndex <- "." ident:Identifier { return ident, nil } / expr:IndexExpression { return expr, nil } IndexExpression "index" <- "[" _? lit:StringLiteral _? "]" { return lit, nil } / "[" _? !StringLiteral &{ return false, errors.New("Invalid index") } / "[" _? StringLiteral _? !"]" &{ return false, errors.New("Unclosed index expression") } Value "value" <- selector:Selector { return &MatchValue{Raw:strings.Join(selector.(Selector), ".")}, nil } / n:NumberLiteral { return &MatchValue{Raw: n.(string)}, nil } / s:StringLiteral { return &MatchValue{Raw: s.(string)}, nil} NumberLiteral "number" <- "-"? IntegerOrFloat &AfterNumbers { return string(c.text), nil } / "-"? IntegerOrFloat !AfterNumbers &{ return false, errors.New("Invalid number literal") } AfterNumbers <- &(_ / EOF / ")") IntegerOrFloat <- ("0" / [1-9][0-9]*) ("." [0-9]+)? StringLiteral "string" <- ('`' RawStringChar* '`' / '"' DoubleStringChar* '"') { return strconv.Unquote(string(c.text)) } / ('`' RawStringChar* / '"' DoubleStringChar*) EOF &{ return false, errors.New("Unterminated string literal") } RawStringChar <- !'`' . DoubleStringChar <- !'"' . _ "whitespace" <- [ \t\r\n]+ EOF <- !.