package filter import ( "fmt" "strconv" "github.com/vapor/errors" ) // ErrBadFilter is returned from Parse when // it encounters an invalid filter expression. var ErrBadFilter = errors.New("invalid query filter") // Predicate represents a parsed filter predicate. type Predicate struct { expr expr selectorTypes map[string]Type Parameters int } // String returns a cleaned, canonical representation of the // predicate. func (p Predicate) String() string { if p.expr == nil { return "" } return p.expr.String() } // MarshalText implements the encoding.TextMarshaler interface and // returns a cleaned, canonical representation of the predicate. func (p Predicate) MarshalText() ([]byte, error) { return []byte(p.expr.String()), nil } // Parse parses a predicate and returns an internal representation of the // predicate or an error if it fails to parse. func Parse(predicate string, tbl *Table, vals []interface{}) (p Predicate, err error) { expr, parser, err := parse(predicate) if err != nil { return p, errors.WithDetail(ErrBadFilter, err.Error()) } selectorTypes, err := typeCheck(expr, tbl, vals) if err != nil { return p, errors.WithDetail(ErrBadFilter, err.Error()) } return Predicate{ expr: expr, selectorTypes: selectorTypes, Parameters: parser.maxPlaceholder, }, nil } // Field is a type for simple expressions that simply access an attribute of // the queried object. They're used for GROUP BYs. type Field struct { expr expr } func (f Field) String() string { return f.expr.String() } // ParseField parses a field expression (either an attrExpr or a selectorExpr). func ParseField(s string) (f Field, err error) { expr, _, err := parse(s) if err != nil { return f, errors.WithDetail(ErrBadFilter, err.Error()) } if expr == nil { return f, errors.WithDetail(ErrBadFilter, "empty field expression") } switch expr.(type) { case attrExpr, selectorExpr: return Field{expr: expr}, nil default: return f, errors.WithDetailf(ErrBadFilter, "%q is not a valid field expression", s) } } func parse(exprString string) (expr expr, parser *parser, err error) { defer func() { r := recover() if perr, ok := r.(parseError); ok { err = perr } else if r != nil { panic(r) } }() parser = newParser([]byte(exprString)) // An empty expression is a valid predicate. if parser.tok == tokEOF { return nil, parser, nil } expr = parseExpr(parser) parser.parseTok(tokEOF) return expr, parser, err } func newParser(src []byte) *parser { p := new(parser) p.scanner.init(src) p.next() // advance onto the first input token return p } // The parser structure holds the parser's internal state. type parser struct { scanner scanner maxPlaceholder int // Current token pos int // token position tok token // one token look-ahead lit string // token literal } func determineBinaryOp(p *parser, minPrecedence int) (op *binaryOp, ok bool) { op, ok = binaryOps[p.lit] return op, ok && op.precedence >= minPrecedence } // next advances to the next token. func (p *parser) next() { p.pos, p.tok, p.lit = p.scanner.Scan() } func (p *parser) parseLit(lit string) { if p.lit != lit { p.errorf("got %s, expected %s", p.lit, lit) } p.next() } func (p *parser) parseTok(tok token) { if p.tok != tok { p.errorf("got %s, expected %s", p.lit, tok.String()) } p.next() } func parseExpr(p *parser) expr { // Uses the precedence-climbing algorithm: // https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method expr := parsePrimaryExpr(p) return parseExprCont(p, expr, 0) } func parseExprCont(p *parser, lhs expr, minPrecedence int) expr { for { op, ok := determineBinaryOp(p, minPrecedence) if !ok { break } p.next() rhs := parsePrimaryExpr(p) for { op2, ok := determineBinaryOp(p, op.precedence+1) if !ok { break } rhs = parseExprCont(p, rhs, op2.precedence) } lhs = binaryExpr{l: lhs, r: rhs, op: op} } return lhs } func parsePrimaryExpr(p *parser) expr { x := parseOperand(p) for p.lit == "." { x = parseSelectorExpr(p, x) } return x } func parseOperand(p *parser) expr { switch { case p.lit == "(": p.next() expr := parseExpr(p) p.parseLit(")") return parenExpr{inner: expr} case p.tok == tokString: v := valueExpr{typ: p.tok, value: p.lit} p.next() return v case p.tok == tokInteger: // Parse the literal into an integer so that we store the string // representation of the *decimal* value, never the hex. integer, err := strconv.ParseInt(p.lit, 0, 64) if err != nil { // can't happen; scanner guarantees it p.errorf("invalid integer: %q", p.lit) } v := valueExpr{typ: p.tok, value: strconv.Itoa(int(integer))} p.next() return v case p.tok == tokPlaceholder: num, err := strconv.Atoi(p.lit[1:]) if err != nil || num <= 0 { p.errorf("invalid placeholder: %q", p.lit) } v := placeholderExpr{num: num} p.next() if num > p.maxPlaceholder { p.maxPlaceholder = num } return v default: return parseEnvironmentExpr(p) } } func parseSelectorExpr(p *parser, objExpr expr) expr { p.next() // move past the '.' ident := p.lit p.parseTok(tokIdent) return selectorExpr{ ident: ident, objExpr: objExpr, } } func parseEnvironmentExpr(p *parser) expr { name := p.lit p.parseTok(tokIdent) if p.lit != "(" { return attrExpr{attr: name} } p.next() expr := parseExpr(p) p.parseLit(")") return envExpr{ ident: name, expr: expr, } } type parseError struct { pos int msg string } func (err parseError) Error() string { return fmt.Sprintf("col %d: %s", err.pos, err.msg) } func (p *parser) errorf(format string, args ...interface{}) { panic(parseError{pos: p.pos, msg: fmt.Sprintf(format, args...)}) }