func compileFilterSet( s string, pos int, parent *types.Filter) (int, error) { for pos < len(s) && s[pos] == '(' { child, newPos, err := compileFilter(s, pos+1) if err != nil { return pos, err } pos = newPos parent.Children = append(parent.Children, child) } if pos == len(s) { return pos, errUnexpectedEOF } return pos + 1, nil }
func compileFilter(s string, pos int) (*types.Filter, int, error) { switch s[pos] { case '(': f, newPos, err := compileFilter(s, pos+1) newPos++ return f, newPos, err case '&': f := &types.Filter{Op: filterAnd} newPos, err := compileFilterSet(s, pos+1, f) return f, newPos, err case '|': f := &types.Filter{Op: filterOr} newPos, err := compileFilterSet(s, pos+1, f) return f, newPos, err case '!': f := &types.Filter{Op: filterNot} child, newPos, err := compileFilter(s, pos+1) f.Children = append(f.Children, child) return f, newPos, err default: var ( f *types.Filter abuf, cbuf bytes.Buffer newPos = pos ) for newPos < len(s) && s[newPos] != ')' { switch { case f != nil: if err := cbuf.WriteByte(s[newPos]); err != nil { return nil, 0, err } case s[newPos] == '=': f = &types.Filter{Op: filterEqualityMatch} case s[newPos] == '>' && s[newPos+1] == '=': f = &types.Filter{Op: filterGreaterOrEqual} newPos++ case s[newPos] == '<' && s[newPos+1] == '=': f = &types.Filter{Op: filterLessOrEqual} newPos++ case s[newPos] == '~' && s[newPos+1] == '=': f = &types.Filter{Op: filterApproxMatch} newPos++ case f == nil: if err := abuf.WriteByte(s[newPos]); err != nil { return nil, 0, err } } newPos++ } if newPos == len(s) { return f, newPos, errUnexpectedEOF } if f == nil { return nil, 0, errParse } f.Left = abuf.String() var ( cbyt = cbuf.Bytes() cstr = cbuf.String() clen = len(cbyt) cfch = cbyt[clen-1] ) switch { case f.Op == filterEqualityMatch && cstr == "*": f.Op = filterPresent case f.Op == filterEqualityMatch && cbyt[0] == '*' && cfch == '*' && clen > 2: f.Op = filterSubstrings f.Right = cstr[1 : clen-1] case f.Op == filterEqualityMatch && cbyt[0] == '*' && clen > 1: f.Op = filterSubstringsPrefix f.Right = cstr[1:] case f.Op == filterEqualityMatch && cfch == '*' && clen > 1: f.Op = filterSubstringsPostfix f.Right = cstr[:clen-1] default: f.Right = cstr } newPos++ return f, newPos, nil } }