1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package adt
16
17 import (
18 "bytes"
19 "strings"
20 )
21
22
23
24
25
26 func BinOp(c *OpContext, op Op, left, right Value) Value {
27 leftKind := left.Kind()
28 rightKind := right.Kind()
29
30 const msg = "non-concrete value '%v' to operation '%s'"
31 if left.Concreteness() > Concrete {
32 return &Bottom{
33 Code: IncompleteError,
34 Err: c.Newf(msg, left, op),
35 }
36 }
37 if right.Concreteness() > Concrete {
38 return &Bottom{
39 Code: IncompleteError,
40 Err: c.Newf(msg, right, op),
41 }
42 }
43
44 if err := CombineErrors(c.src, left, right); err != nil {
45 return err
46 }
47
48 switch op {
49 case EqualOp:
50 switch {
51 case leftKind == NullKind && rightKind == NullKind:
52 return c.newBool(true)
53
54 case leftKind == NullKind || rightKind == NullKind:
55 return c.newBool(false)
56
57 case leftKind == BoolKind:
58 return c.newBool(c.BoolValue(left) == c.BoolValue(right))
59
60 case leftKind == StringKind:
61
62 return cmpTonode(c, op, strings.Compare(c.StringValue(left), c.StringValue(right)))
63
64 case leftKind == BytesKind:
65 return cmpTonode(c, op, bytes.Compare(c.bytesValue(left, op), c.bytesValue(right, op)))
66
67 case leftKind&NumKind != 0 && rightKind&NumKind != 0:
68
69 return cmpTonode(c, op, c.Num(left, op).X.Cmp(&c.Num(right, op).X))
70
71 case leftKind == ListKind && rightKind == ListKind:
72 x := c.Elems(left)
73 y := c.Elems(right)
74 if len(x) != len(y) {
75 return c.newBool(false)
76 }
77 for i, e := range x {
78 a, _ := c.concrete(nil, e, op)
79 b, _ := c.concrete(nil, y[i], op)
80 if !test(c, EqualOp, a, b) {
81 return c.newBool(false)
82 }
83 }
84 return c.newBool(true)
85 }
86
87 case NotEqualOp:
88 switch {
89 case leftKind == NullKind && rightKind == NullKind:
90 return c.newBool(false)
91
92 case leftKind == NullKind || rightKind == NullKind:
93 return c.newBool(true)
94
95 case leftKind == BoolKind:
96 return c.newBool(c.boolValue(left, op) != c.boolValue(right, op))
97
98 case leftKind == StringKind:
99
100 return cmpTonode(c, op, strings.Compare(c.StringValue(left), c.StringValue(right)))
101
102 case leftKind == BytesKind:
103 return cmpTonode(c, op, bytes.Compare(c.bytesValue(left, op), c.bytesValue(right, op)))
104
105 case leftKind&NumKind != 0 && rightKind&NumKind != 0:
106
107 return cmpTonode(c, op, c.Num(left, op).X.Cmp(&c.Num(right, op).X))
108
109 case leftKind == ListKind && rightKind == ListKind:
110 x := c.Elems(left)
111 y := c.Elems(right)
112 if len(x) != len(y) {
113 return c.newBool(true)
114 }
115 for i, e := range x {
116 a, _ := c.concrete(nil, e, op)
117 b, _ := c.concrete(nil, y[i], op)
118 if !test(c, EqualOp, a, b) {
119 return c.newBool(true)
120 }
121 }
122 return c.newBool(false)
123 }
124
125 case LessThanOp, LessEqualOp, GreaterEqualOp, GreaterThanOp:
126 switch {
127 case leftKind == StringKind && rightKind == StringKind:
128
129 return cmpTonode(c, op, strings.Compare(c.stringValue(left, op), c.stringValue(right, op)))
130
131 case leftKind == BytesKind && rightKind == BytesKind:
132 return cmpTonode(c, op, bytes.Compare(c.bytesValue(left, op), c.bytesValue(right, op)))
133
134 case leftKind&NumKind != 0 && rightKind&NumKind != 0:
135
136 return cmpTonode(c, op, c.Num(left, op).X.Cmp(&c.Num(right, op).X))
137 }
138
139 case BoolAndOp:
140 return c.newBool(c.boolValue(left, op) && c.boolValue(right, op))
141
142 case BoolOrOp:
143 return c.newBool(c.boolValue(left, op) || c.boolValue(right, op))
144
145 case MatchOp:
146
147
148
149
150
151
152
153
154 return c.newBool(c.regexp(right).MatchString(c.stringValue(left, op)))
155
156 case NotMatchOp:
157 return c.newBool(!c.regexp(right).MatchString(c.stringValue(left, op)))
158
159 case AddOp:
160 switch {
161 case leftKind&NumKind != 0 && rightKind&NumKind != 0:
162 return c.Add(c.Num(left, op), c.Num(right, op))
163
164 case leftKind == StringKind && rightKind == StringKind:
165 return c.NewString(c.StringValue(left) + c.StringValue(right))
166
167 case leftKind == BytesKind && rightKind == BytesKind:
168 ba := c.bytesValue(left, op)
169 bb := c.bytesValue(right, op)
170 b := make([]byte, len(ba)+len(bb))
171 copy(b, ba)
172 copy(b[len(ba):], bb)
173 return c.newBytes(b)
174
175 case leftKind == ListKind && rightKind == ListKind:
176
177
178
179 if err := c.Err(); err != nil {
180 return err
181 }
182
183 x := MakeIdentLabel(c, "x", "")
184
185
186 forClause := func(src Expr) *Comprehension {
187 s := &StructLit{Decls: []Decl{
188 &FieldReference{UpCount: 1, Label: x},
189 }}
190 return &Comprehension{
191 Clauses: []Yielder{
192 &ForClause{
193 Value: x,
194 Src: src,
195 },
196 },
197 Value: s,
198 }
199 }
200
201 list := &ListLit{
202 Elems: []Elem{
203 forClause(left),
204 forClause(right),
205 },
206 }
207
208 n := c.newInlineVertex(nil, nil, MakeConjunct(c.Env(0), list, c.ci))
209 n.CompleteArcs(c)
210
211 return n
212 }
213
214 case SubtractOp:
215 return c.Sub(c.Num(left, op), c.Num(right, op))
216
217 case MultiplyOp:
218 switch {
219
220 case leftKind&NumKind != 0 && rightKind&NumKind != 0:
221 return c.Mul(c.Num(left, op), c.Num(right, op))
222
223 case leftKind == StringKind && rightKind == IntKind:
224 const as = "string multiplication"
225 return c.NewString(strings.Repeat(c.stringValue(left, as), int(c.uint64(right, as))))
226
227 case leftKind == IntKind && rightKind == StringKind:
228 const as = "string multiplication"
229 return c.NewString(strings.Repeat(c.stringValue(right, as), int(c.uint64(left, as))))
230
231 case leftKind == BytesKind && rightKind == IntKind:
232 const as = "bytes multiplication"
233 return c.newBytes(bytes.Repeat(c.bytesValue(left, as), int(c.uint64(right, as))))
234
235 case leftKind == IntKind && rightKind == BytesKind:
236 const as = "bytes multiplication"
237 return c.newBytes(bytes.Repeat(c.bytesValue(right, as), int(c.uint64(left, as))))
238
239 case leftKind == ListKind && rightKind == IntKind:
240 left, right = right, left
241 fallthrough
242
243 case leftKind == IntKind && rightKind == ListKind:
244
245
246 list := &ListLit{}
247 x := MakeIdentLabel(c, "x", "")
248
249 for i := c.uint64(left, "list multiplier"); i > 0; i-- {
250 st := &StructLit{Decls: []Decl{
251 &FieldReference{UpCount: 1, Label: x},
252 }}
253 list.Elems = append(list.Elems,
254 &Comprehension{
255 Clauses: []Yielder{
256 &ForClause{
257 Value: x,
258 Src: right,
259 },
260 },
261 Value: st,
262 },
263 )
264 }
265 if err := c.Err(); err != nil {
266 return err
267 }
268
269 n := c.newInlineVertex(nil, nil, MakeConjunct(c.Env(0), list, c.ci))
270 n.CompleteArcs(c)
271
272 return n
273 }
274
275 case FloatQuotientOp:
276 if leftKind&NumKind != 0 && rightKind&NumKind != 0 {
277 return c.Quo(c.Num(left, op), c.Num(right, op))
278 }
279
280 case IntDivideOp:
281 if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
282 return c.IntDiv(c.Num(left, op), c.Num(right, op))
283 }
284
285 case IntModuloOp:
286 if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
287 return c.IntMod(c.Num(left, op), c.Num(right, op))
288 }
289
290 case IntQuotientOp:
291 if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
292 return c.IntQuo(c.Num(left, op), c.Num(right, op))
293 }
294
295 case IntRemainderOp:
296 if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
297 return c.IntRem(c.Num(left, op), c.Num(right, op))
298 }
299 }
300
301 return c.NewErrf("invalid operands %s and %s to '%s' (type %s and %s)",
302 left, right, op, left.Kind(), right.Kind())
303 }
304
305 func cmpTonode(c *OpContext, op Op, r int) Value {
306 result := false
307 switch op {
308 case LessThanOp:
309 result = r == -1
310 case LessEqualOp:
311 result = r != 1
312 case EqualOp, AndOp:
313 result = r == 0
314 case NotEqualOp:
315 result = r != 0
316 case GreaterEqualOp:
317 result = r != -1
318 case GreaterThanOp:
319 result = r == 1
320 }
321 return c.newBool(result)
322 }
323
View as plain text