github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/pubsub/query/syntax/parser.go (about) 1 package syntax 2 3 import ( 4 "fmt" 5 "io" 6 "math" 7 "strconv" 8 "strings" 9 "time" 10 ) 11 12 // Parse parses the specified query string. It is shorthand for constructing a 13 // parser for s and calling its Parse method. 14 func Parse(s string) (Query, error) { 15 return NewParser(strings.NewReader(s)).Parse() 16 } 17 18 // Query is the root of the parse tree for a query. A query is the conjunction 19 // of one or more conditions. 20 type Query []Condition 21 22 func (q Query) String() string { 23 ss := make([]string, len(q)) 24 for i, cond := range q { 25 ss[i] = cond.String() 26 } 27 return strings.Join(ss, " AND ") 28 } 29 30 // A Condition is a single conditional expression, consisting of a tag, a 31 // comparison operator, and an optional argument. The type of the argument 32 // depends on the operator. 33 type Condition struct { 34 Tag string 35 Op Token 36 Arg *Arg 37 38 opText string 39 } 40 41 func (c Condition) String() string { 42 s := c.Tag + " " + c.opText 43 if c.Arg != nil { 44 return s + " " + c.Arg.String() 45 } 46 return s 47 } 48 49 // An Arg is the argument of a comparison operator. 50 type Arg struct { 51 Type Token 52 text string 53 } 54 55 func (a *Arg) String() string { 56 if a == nil { 57 return "" 58 } 59 switch a.Type { 60 case TString: 61 return "'" + a.text + "'" 62 case TTime: 63 return "TIME " + a.text 64 case TDate: 65 return "DATE " + a.text 66 default: 67 return a.text 68 } 69 } 70 71 // Number returns the value of the argument text as a number, or a NaN if the 72 // text does not encode a valid number value. 73 func (a *Arg) Number() float64 { 74 if a == nil { 75 return -1 76 } 77 v, err := strconv.ParseFloat(a.text, 64) 78 if err == nil && v >= 0 { 79 return v 80 } 81 return math.NaN() 82 } 83 84 // Time returns the value of the argument text as a time, or the zero value if 85 // the text does not encode a timestamp or datestamp. 86 func (a *Arg) Time() time.Time { 87 var ts time.Time 88 if a == nil { 89 return ts 90 } 91 var err error 92 switch a.Type { 93 case TDate: 94 ts, err = ParseDate(a.text) 95 case TTime: 96 ts, err = ParseTime(a.text) 97 } 98 if err == nil { 99 return ts 100 } 101 return time.Time{} 102 } 103 104 // Value returns the value of the argument text as a string, or "". 105 func (a *Arg) Value() string { 106 if a == nil { 107 return "" 108 } 109 return a.text 110 } 111 112 // Parser is a query expression parser. The grammar for query expressions is 113 // defined in the syntax package documentation. 114 type Parser struct { 115 scanner *Scanner 116 } 117 118 // NewParser constructs a new parser that reads the input from r. 119 func NewParser(r io.Reader) *Parser { 120 return &Parser{scanner: NewScanner(r)} 121 } 122 123 // Parse parses the complete input and returns the resulting query. 124 func (p *Parser) Parse() (Query, error) { 125 cond, err := p.parseCond() 126 if err != nil { 127 return nil, err 128 } 129 conds := []Condition{cond} 130 for p.scanner.Next() != io.EOF { 131 if tok := p.scanner.Token(); tok != TAnd { 132 return nil, fmt.Errorf("offset %d: got %v, want %v", p.scanner.Pos(), tok, TAnd) 133 } 134 cond, err := p.parseCond() 135 if err != nil { 136 return nil, err 137 } 138 conds = append(conds, cond) 139 } 140 return conds, nil 141 } 142 143 // parseCond parses a conditional expression: tag OP value. 144 func (p *Parser) parseCond() (Condition, error) { 145 var cond Condition 146 if err := p.require(TTag); err != nil { 147 return cond, err 148 } 149 cond.Tag = p.scanner.Text() 150 if err := p.require(TLeq, TGeq, TLt, TGt, TEq, TContains, TExists); err != nil { 151 return cond, err 152 } 153 cond.Op = p.scanner.Token() 154 cond.opText = p.scanner.Text() 155 156 var err error 157 switch cond.Op { 158 case TLeq, TGeq, TLt, TGt: 159 err = p.require(TNumber, TTime, TDate) 160 case TEq: 161 err = p.require(TNumber, TTime, TDate, TString) 162 case TContains: 163 err = p.require(TString) 164 case TExists: 165 // no argument 166 return cond, nil 167 default: 168 return cond, fmt.Errorf("offset %d: unexpected operator %v", p.scanner.Pos(), cond.Op) 169 } 170 if err != nil { 171 return cond, err 172 } 173 cond.Arg = &Arg{Type: p.scanner.Token(), text: p.scanner.Text()} 174 return cond, nil 175 } 176 177 // require advances the scanner and requires that the resulting token is one of 178 // the specified token types. 179 func (p *Parser) require(tokens ...Token) error { 180 if err := p.scanner.Next(); err != nil { 181 return fmt.Errorf("offset %d: %w", p.scanner.Pos(), err) 182 } 183 got := p.scanner.Token() 184 for _, tok := range tokens { 185 if tok == got { 186 return nil 187 } 188 } 189 return fmt.Errorf("offset %d: got %v, wanted %s", p.scanner.Pos(), got, tokLabel(tokens)) 190 } 191 192 // tokLabel makes a human-readable summary string for the given token types. 193 func tokLabel(tokens []Token) string { 194 if len(tokens) == 1 { 195 return tokens[0].String() 196 } 197 last := len(tokens) - 1 198 ss := make([]string, len(tokens)-1) 199 for i, tok := range tokens[:last] { 200 ss[i] = tok.String() 201 } 202 return strings.Join(ss, ", ") + " or " + tokens[last].String() 203 } 204 205 // ParseDate parses s as a date string in the format used by DATE values. 206 func ParseDate(s string) (time.Time, error) { 207 return time.Parse("2006-01-02", s) 208 } 209 210 // ParseTime parses s as a timestamp in the format used by TIME values. 211 func ParseTime(s string) (time.Time, error) { 212 return time.Parse(time.RFC3339, s) 213 }