OSDN Git Service

new repo
[bytom/vapor.git] / blockchain / query / filter / typecheck.go
1 package filter
2
3 import (
4         "fmt"
5
6         "github.com/vapor/errors"
7 )
8
9 //Column describe a column
10 type Column struct {
11         Name string
12         Type Type
13 }
14
15 //Table describe a table
16 type Table struct {
17         Name        string
18         Alias       string
19         Columns     map[string]*Column
20         ForeignKeys map[string]*ForeignKey
21 }
22
23 //ForeignKey describe a foreign key
24 type ForeignKey struct {
25         Table         *Table
26         LocalColumn   string
27         ForeignColumn string
28 }
29
30 func isType(got Type, want Type) bool {
31         return got == want || got == Any
32 }
33
34 func knownType(t Type) bool {
35         return t == Bool || t == String || t == Integer || t == Object
36 }
37
38 func valueTypes(vals []interface{}) ([]Type, error) {
39         valTypes := make([]Type, len(vals))
40         for i, val := range vals {
41                 switch val.(type) {
42                 case int, uint, int32, uint32, int64, uint64:
43                         valTypes[i] = Integer
44                 case string:
45                         valTypes[i] = String
46                 case bool:
47                         valTypes[i] = Bool
48                 default:
49                         return nil, fmt.Errorf("unsupported value type %T", val)
50                 }
51         }
52         return valTypes, nil
53 }
54
55 // typeCheck will statically type check expr with vals as the parameters
56 // and using tbl to determine available attributes and environments. It
57 // returns the inferred types of arbitrary json keys as a map.
58 func typeCheck(expr expr, tbl *Table, vals []interface{}) (map[string]Type, error) {
59         valTypes, err := valueTypes(vals)
60         if err != nil {
61                 return nil, err
62         }
63         selectorTypes := make(map[string]Type)
64         typ, err := typeCheckExpr(expr, tbl, valTypes, selectorTypes)
65         if err != nil {
66                 return nil, err
67         }
68         ok, err := assertType(expr, typ, Bool, selectorTypes)
69         if err != nil {
70                 return nil, err
71         }
72         if !ok {
73                 return nil, fmt.Errorf("filter predicate must evaluate to bool, got %s", typ)
74         }
75         return selectorTypes, nil
76 }
77
78 func typeCheckExpr(expr expr, tbl *Table, valTypes []Type, selectorTypes map[string]Type) (typ Type, err error) {
79         if expr == nil { // no expr is a valid, bool type
80                 return Bool, nil
81         }
82
83         switch e := expr.(type) {
84         case parenExpr:
85                 return typeCheckExpr(e.inner, tbl, valTypes, selectorTypes)
86         case binaryExpr:
87                 leftTyp, err := typeCheckExpr(e.l, tbl, valTypes, selectorTypes)
88                 if err != nil {
89                         return leftTyp, err
90                 }
91                 rightTyp, err := typeCheckExpr(e.r, tbl, valTypes, selectorTypes)
92                 if err != nil {
93                         return rightTyp, err
94                 }
95
96                 switch e.op.name {
97                 case "OR", "AND":
98                         ok, err := assertType(e.l, leftTyp, Bool, selectorTypes)
99                         if err != nil {
100                                 return typ, err
101                         }
102                         if !ok {
103                                 return typ, fmt.Errorf("%s expects bool operands", e.op.name)
104                         }
105
106                         ok, err = assertType(e.r, rightTyp, Bool, selectorTypes)
107                         if err != nil {
108                                 return typ, err
109                         }
110                         if !ok {
111                                 return typ, fmt.Errorf("%s expects bool operands", e.op.name)
112                         }
113                         return Bool, nil
114                 case "=":
115                         // The = operand requires left and right types to be equal. If
116                         // one of our types is known but the other is not, we need to
117                         // coerce the untyped one to a matching type.
118                         if !knownType(leftTyp) && knownType(rightTyp) {
119                                 err := setType(e.l, rightTyp, selectorTypes)
120                                 if err != nil {
121                                         return leftTyp, err
122                                 }
123                                 leftTyp = rightTyp
124                         }
125                         if !knownType(rightTyp) && knownType(leftTyp) {
126                                 err := setType(e.r, leftTyp, selectorTypes)
127                                 if err != nil {
128                                         return leftTyp, err
129                                 }
130                                 rightTyp = leftTyp
131                         }
132                         if !isType(leftTyp, String) && !isType(leftTyp, Integer) {
133                                 return typ, fmt.Errorf("%s expects integer or string operands", e.op.name)
134                         }
135                         if !isType(rightTyp, String) && !isType(rightTyp, Integer) {
136                                 return typ, fmt.Errorf("%s expects integer or string operands", e.op.name)
137                         }
138                         if knownType(rightTyp) && knownType(leftTyp) && leftTyp != rightTyp {
139                                 return typ, fmt.Errorf("%s expects operands of matching types", e.op.name)
140                         }
141                         return Bool, nil
142                 default:
143                         panic(fmt.Errorf("unsupported operator: %s", e.op.name))
144                 }
145         case placeholderExpr:
146                 if len(valTypes) == 0 {
147                         return Any, nil
148                 }
149                 if e.num <= 0 || e.num > len(valTypes) {
150                         return typ, fmt.Errorf("unbound placeholder: $%d", e.num)
151                 }
152                 return valTypes[e.num-1], nil
153         case attrExpr:
154                 col, ok := tbl.Columns[e.attr]
155                 if !ok {
156                         return typ, fmt.Errorf("invalid attribute: %s", e.attr)
157                 }
158                 return col.Type, nil
159         case valueExpr:
160                 switch e.typ {
161                 case tokString:
162                         return String, nil
163                 case tokInteger:
164                         return Integer, nil
165                 default:
166                         panic(fmt.Errorf("value expr with invalid token type: %s", e.typ))
167                 }
168         case selectorExpr:
169                 typ, err = typeCheckExpr(e.objExpr, tbl, valTypes, selectorTypes)
170                 if err != nil {
171                         return typ, err
172                 }
173                 ok, err := assertType(e.objExpr, typ, Object, selectorTypes)
174                 if err != nil {
175                         return typ, err
176                 }
177                 if !ok {
178                         return typ, errors.New("selector `.` can only be used on objects")
179                 }
180
181                 // Unfortunately, we can't know the type of the field within the
182                 // object yet. Depending on the context, we might be able to assign it
183                 // a type later in setType.
184                 return Any, nil
185         case envExpr:
186                 fk, ok := tbl.ForeignKeys[e.ident]
187                 if !ok {
188                         return typ, fmt.Errorf("invalid environment `%s`", e.ident)
189                 }
190                 typ, err = typeCheckExpr(e.expr, fk.Table, valTypes, selectorTypes)
191                 if err != nil {
192                         return typ, err
193                 }
194                 ok, err = assertType(e.expr, typ, Bool, selectorTypes)
195                 if err != nil {
196                         return typ, err
197                 }
198                 if !ok {
199                         return typ, errors.New(e.ident + "(...) body must have type bool")
200                 }
201                 return Bool, nil
202         default:
203                 panic(fmt.Errorf("unrecognized expr type %T", expr))
204         }
205 }
206
207 func assertType(expr expr, got, want Type, selectorTypes map[string]Type) (bool, error) {
208         if !isType(got, want) { // type does not match
209                 return false, nil
210         }
211         if got != Any { // matching type *and* it's a concrete type
212                 return true, nil
213         }
214         // got is `Any`. we should restrict expr to be `want`.
215         err := setType(expr, want, selectorTypes)
216         return true, err
217 }
218
219 func setType(expr expr, typ Type, selectorTypes map[string]Type) error {
220         switch e := expr.(type) {
221         case parenExpr:
222                 return setType(e.inner, typ, selectorTypes)
223         case placeholderExpr:
224                 // This is a special case for when we parse a txfeed filter at
225                 // txfeed creation time. We don't have access to concrete values
226                 // yet, so the parameters are untyped.
227                 return nil
228         case selectorExpr:
229                 /*path := strings.Join(jsonbPath(expr), ".")
230                 boundTyp, ok := selectorTypes[path]
231                 if ok && boundTyp != typ {
232                         return fmt.Errorf("%q used as both %s and %s", path, boundTyp, typ)
233                 }
234                 selectorTypes[path] = typ*/
235                 return nil
236         default:
237                 // This should be impossible because all other expressions are
238                 // strongly typed.
239                 panic(fmt.Errorf("unexpected setType on %T", expr))
240         }
241 }