blob: 262af6b70b0aef9c7fb0fcb9bf54a42baef28af0 [file] [log] [blame]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001// Copyright 2018 The CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cue
16
17import (
18 "flag"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010019 "testing"
20
21 "cuelang.org/go/cue/errors"
22 "cuelang.org/go/cue/parser"
23 "cuelang.org/go/cue/token"
24)
25
26var traceOn = flag.Bool("debug", false, "enable tracing")
27
28func compileFileWithErrors(t *testing.T, body string) (*context, *structLit, errors.List) {
29 t.Helper()
30 ctx, inst, errs := compileInstance(t, body)
31 return ctx, inst.rootValue.evalPartial(ctx).(*structLit), errs
32}
33
34func compileFile(t *testing.T, body string) (*context, *structLit) {
35 t.Helper()
36 ctx, inst, errs := compileInstance(t, body)
37 if errs != nil {
38 t.Fatal(errs)
39 }
40 return ctx, inst.rootValue.evalPartial(ctx).(*structLit)
41}
42
43func compileInstance(t *testing.T, body string) (*context, *Instance, errors.List) {
44 t.Helper()
45
46 fset := token.NewFileSet()
47 x := newIndex(fset).NewInstance(nil)
Marcel van Lohuizen2bf066f2018-12-16 11:43:49 +010048 f, err := parser.ParseFile(fset, "test", body)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010049 ctx := x.newContext()
50
51 switch errs := err.(type) {
52 case nil:
53 x.insertFile(f)
54 case errors.List:
55 return ctx, x, errs
56 default:
57 t.Fatal(err)
58 }
59 return ctx, x, nil
60}
61
62func rewriteHelper(t *testing.T, cases []testCase, r rewriteMode) {
63 t.Helper()
64 for _, tc := range cases {
65 t.Run(tc.desc, func(t *testing.T) {
66 t.Helper()
67 ctx, obj := compileFile(t, tc.in)
68 ctx.trace = *traceOn
69 root := testResolve(ctx, obj, r)
70
71 got := debugStr(ctx, root)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010072
73 // Copy the result
74 if got != tc.out {
75 fn := t.Errorf
76 if tc.skip {
77 fn = t.Skipf
78 }
79 fn("output differs:\ngot %s\nwant %s", got, tc.out)
80 }
81 })
82 }
83}
84
85type testCase struct {
86 desc string
87 in string
88 out string
89 skip bool
90}
91
92func TestBasicRewrite(t *testing.T) {
93 testCases := []testCase{{
94 desc: "errors",
95 in: `
96 a: _|_ & _|_
97 b: null & _|_
98 c: b.a == _|_
99 d: _|_ != b.a
100 e: _|_ == _|_
101 `,
102 out: `<0>{a: _|_(from source), b: _|_(from source), c: true, d: false, e: true}`,
103 }, {
Marcel van Lohuizen706e69c2019-02-11 18:21:14 +0100104 desc: "regexp",
105 in: `
106 c1: "a" =~ "a"
107 c2: "foo" =~ "[a-z]{3}"
108 c3: "foo" =~ "[a-z]{4}"
109 c4: "foo" !~ "[a-z]{4}"
110
111 b1: =~ "a"
112 b1: "a"
113 b2: =~ "[a-z]{3}"
114 b2: "foo"
115 b3: =~ "[a-z]{4}"
116 b3: "foo"
117 b4: !~ "[a-z]{4}"
118 b4: "foo"
119
120 s1: != "b" & =~"c" // =~"c"
121 s2: != "b" & =~"[a-z]" // != "b" & =~"[a-z]"
122
123 e1: "foo" =~ 1
124 e2: "foo" !~ true
125 e3: != "a" & <5
126 `,
127 out: `<0>{c1: true, ` +
128 `c2: true, ` +
129 `c3: false, ` +
130 `c4: true, ` +
131
132 `b1: "a", ` +
133 `b2: "foo", ` +
134 `b3: _|_((=~"[a-z]{4}" & "foo"):"foo" does not match =~"[a-z]{4}"), ` +
135 `b4: "foo", ` +
136
137 `s1: =~"c", ` +
138 `s2: (!="b" & =~"[a-z]"), ` +
139
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200140 `e1: _|_(("foo" =~ 1):unsupported op =~(string, int)), ` +
Marcel van Lohuizen706e69c2019-02-11 18:21:14 +0100141 `e2: _|_(("foo" !~ true):unsupported op !~(string, bool)), ` +
142 `e3: _|_((!="a" & <5):unsupported op &((string)*, (number)*))}`,
143 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100144 desc: "arithmetic",
145 in: `
Marcel van Lohuizen0a7717d2019-02-13 17:36:32 +0400146 i1: 1 & int
147 i2: 2 & int
148
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100149 sum: -1 + +2 // 1
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100150 div1: 2.0 / 3 * 6 // 4
151 div2: 2 / 3 * 6 // 4
152 rem: 2 % 3 // 2
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100153 b: 1 != 4
Marcel van Lohuizen0a7717d2019-02-13 17:36:32 +0400154
155 v1: 1.0T/2.0
156 v2: 2.0 == 2
157 v3: 2.0/3.0
158 v4: 2.0%3.0
159 v5: i1 div i2
160
161 e0: 2 + "a"
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200162 // these are now all alloweed
163 // e1: 2.0 / i1
164 // e2: i1 / 2.0
165 // e3: 3.0 % i2
166 // e4: i1 % 2.0
Marcel van Lohuizen0a7717d2019-02-13 17:36:32 +0400167 e5: 1.0 div 2
168 e6: 2 rem 2.0
169 e7: 2 quo 2.0
170 e8: 1.0 mod 1
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100171 `,
Marcel van Lohuizen0a7717d2019-02-13 17:36:32 +0400172 out: `<0>{i1: 1, i2: 2, ` +
173 `sum: 1, ` +
Marcel van Lohuizen0a7717d2019-02-13 17:36:32 +0400174 `div1: 4.00000000000000000000000, ` +
175 `div2: 4.00000000000000000000000, ` +
176 `rem: 2, ` +
177 `b: true, ` +
178 `v1: 5e+11, ` +
179 `v2: true, ` +
180 `v3: 0.666666666666666666666667, ` +
181 `v4: 2.0, ` +
182 `v5: 0, ` +
183
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200184 `e0: _|_((2 + "a"):unsupported op +(int, string)), ` +
185 // `e1: _|_((2.0 / 1):unsupported op /(float, int)), ` +
186 // `e2: _|_((1 / 2.0):unsupported op /(int, float)), ` +
187 // `e3: _|_((3.0 % 2):unsupported op %(float, int)), ` +
188 // `e4: _|_((1 % 2.0):unsupported op %(int, float)), ` +
189 `e5: _|_((1.0 div 2):unsupported op div(float, int)), ` +
190 `e6: _|_((2 rem 2.0):unsupported op rem(int, float)), ` +
191 `e7: _|_((2 quo 2.0):unsupported op quo(int, float)), ` +
192 `e8: _|_((1.0 mod 1):unsupported op mod(float, int))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100193 }, {
194 desc: "integer-specific arithmetic",
195 in: `
196 q1: 5 quo 2 // 2
197 q2: 5 quo -2 // -2
198 q3: -5 quo 2 // -2
199 q4: -5 quo -2 // 2
200 qe1: 2.0 quo 1
201 qe2: 2 quo 1.0
202
203 r1: 5 rem 2 // 1
204 r2: 5 rem -2 // 1
205 r3: -5 rem 2 // -1
206 r4: -5 rem -2 // -1
207 re1: 2.0 rem 1
208 re2: 2 rem 1.0
209
210 d1: 5 div 2 // 2
211 d2: 5 div -2 // -2
212 d3: -5 div 2 // -3
213 d4: -5 div -2 // 3
214 de1: 2.0 div 1
215 de2: 2 div 1.0
216
217 m1: 5 mod 2 // 1
218 m2: 5 mod -2 // 1
219 m3: -5 mod 2 // 1
220 m4: -5 mod -2 // 1
221 me1: 2.0 mod 1
222 me2: 2 mod 1.0
223
224 // TODO: handle divide by zero
225 `,
226 out: `<0>{q1: 2, q2: -2, q3: -2, q4: 2, ` +
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200227 `qe1: _|_((2.0 quo 1):unsupported op quo(float, int)), ` +
228 `qe2: _|_((2 quo 1.0):unsupported op quo(int, float)), ` +
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100229 `r1: 1, r2: 1, r3: -1, r4: -1, re1: ` +
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200230 `_|_((2.0 rem 1):unsupported op rem(float, int)), ` +
231 `re2: _|_((2 rem 1.0):unsupported op rem(int, float)), ` +
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100232 `d1: 2, d2: -2, d3: -3, d4: 3, ` +
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200233 `de1: _|_((2.0 div 1):unsupported op div(float, int)), ` +
234 `de2: _|_((2 div 1.0):unsupported op div(int, float)), ` +
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100235 `m1: 1, m2: 1, m3: 1, m4: 1, ` +
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200236 `me1: _|_((2.0 mod 1):unsupported op mod(float, int)), ` +
237 `me2: _|_((2 mod 1.0):unsupported op mod(int, float))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100238 }, {
239 desc: "booleans",
240 in: `
241 t: true
242 t: !false
243 f: false
244 f: !t
245 e: true
246 e: !true
247 `,
248 out: "<0>{t: true, f: false, e: _|_(true:failed to unify: true != false)}",
249 }, {
250 desc: "boolean arithmetic",
251 in: `
252 a: true && true
253 b: true || false
254 c: false == true
255 d: false != true
256 e: true & true
257 f: true & false
258 `,
259 out: "<0>{a: true, b: true, c: false, d: true, e: true, f: _|_(true:failed to unify: true != false)}",
260 }, {
261 desc: "basic type",
262 in: `
263 a: 1 & int
264 b: number & 1
265 c: 1.0
266 c: float
267 d: int & float // _|_
268 e: "4" & string
269 f: true
270 f: bool
271 `,
272 out: `<0>{a: 1, b: 1, c: 1.0, d: _|_((int & float):unsupported op &((int)*, (float)*)), e: "4", f: true}`,
273 }, {
Marcel van Lohuizend401e722019-02-21 22:59:31 +0100274 desc: "strings and bytes",
275 in: `
276 s0: "foo" + "bar"
277 s1: 3 * "abc"
278 s2: "abc" * 2
279
280 b0: 'foo' + 'bar'
281 b1: 3 * 'abc'
282 b2: 'abc' * 2
Marcel van Lohuizen09d814d2019-02-22 19:14:33 +0100283
284 // TODO: consider the semantics of this and perhaps allow this.
285 e0: "a" + ''
286 e1: 'b' + "c"
Marcel van Lohuizend401e722019-02-21 22:59:31 +0100287 `,
288 out: `<0>{` +
289 `s0: "foobar", ` +
290 `s1: "abcabcabc", ` +
291 `s2: "abcabc", ` +
292 `b0: 'foobar', ` +
293 `b1: 'abcabcabc', ` +
Marcel van Lohuizen09d814d2019-02-22 19:14:33 +0100294 `b2: 'abcabc', ` +
295
296 `e0: _|_(("a" + ''):unsupported op +(string, bytes)), ` +
297 `e1: _|_(('b' + "c"):unsupported op +(bytes, string))` +
Marcel van Lohuizend401e722019-02-21 22:59:31 +0100298 `}`,
299 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100300 desc: "escaping",
301
302 in: `
303 a: "foo\nbar",
304 b: a,
305
306 // TODO: mimic http://exploringjs.com/es6/ch_template-literals.html#sec_introduction-template-literals
307 `,
308 out: `<0>{a: "foo\nbar", b: "foo\nbar"}`,
309 // out: `<0>{a: "foo\nbar", b: <0>.a}`,
310 }, {
311 desc: "reference",
312 in: `
313 a: b
314 b: 2
315 d: {
316 d: 3
317 e: d
318 }
319 e: {
320 e: {
321 v: 1
322 }
323 f: {
324 v: e.v
325 }
326 }
327 `,
328 out: "<0>{a: 2, b: 2, d: <1>{d: 3, e: 3}, e: <2>{e: <3>{v: 1}, f: <4>{v: 1}}}",
329 }, {
330 desc: "lists",
331 in: `
332 list: [1,2,3]
333 index: [1,2,3][1]
334 unify: [1,2,3] & [_,2,3]
335 e: [] & 4
336 e2: [3]["d"]
337 e3: [3][-1]
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100338 e4: [1, 2, ...>=4 & <=5] & [1, 2, 4, 8]
339 e5: [1, 2, 4, 8] & [1, 2, ...>=4 & <=5]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100340 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200341 out: `<0>{list: [1,2,3], index: 2, unify: [1,2,3], e: _|_(([] & 4):unsupported op &(list, int)), e2: _|_("d":invalid list index "d" (type string)), e3: _|_(-1:invalid list index -1 (index must be non-negative)), e4: [1,2,4,_|_((<=5 & 8):8 not within bound <=5)], e5: [1,2,4,_|_((<=5 & 8):8 not within bound <=5)]}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100342 }, {
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500343 desc: "list arithmetic",
344 in: `
345 list: [1,2,3]
346 mul0: list*0
347 mul1: list*1
348 mul2: 2*list
349 list1: [1]
350 mul1_0: list1*0
351 mul1_1: 1*list1
352 mul1_2: list1*2
353 e: list*-1
354 `,
355 out: `<0>{list: [1,2,3], ` +
356 `mul0: [], ` +
357 `mul1: [1,2,3], ` +
358 `mul2: [1,2,3,1,2,3], ` +
359 `list1: [1], ` +
360 `mul1_0: [], ` +
361 `mul1_1: [1], ` +
362 `mul1_2: [1,1], ` +
363 `e: _|_((<1>.list * -1):negative number -1 multiplies list)}`,
364 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100365 desc: "selecting",
366 in: `
367 obj: {a: 1, b: 2}
368 index: {a: 1, b: 2}["b"]
369 mulidx: {a: 1, b: {a:1, b: 3}}["b"]["b"]
370 e: {a: 1}[4]
371 f: {a: 1}.b
372 g: {a: 1}["b"]
373 h: [3].b
374 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200375 out: `<0>{obj: <1>{a: 1, b: 2}, index: 2, mulidx: 3, e: _|_(4:invalid struct index 4 (type int)), f: _|_(<2>{a: 1}.b:undefined field "b"), g: _|_(<3>{a: 1}["b"]:undefined field "b"), h: _|_([3]:invalid operation: [3].b (type list does not support selection))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100376 }, {
377 desc: "obj unify",
378 in: `
379 o1: {a: 1 } & { b: 2} // {a:1,b:2}
380 o2: {a: 1, b:2 } & { b: 2} // {a:1,b:2}
381 o3: {a: 1 } & { a:1, b: 2} // {a:1,b:2}
382 o4: {a: 1 } & { b: 2} // {a:1,b:2}
383 o4: {a: 1, b:2 } & { b: 2}
384 o4: {a: 1 } & { a:1, b: 2}
385 e: 1 // 1 & {a:3}
386 e: {a:3}
387 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200388 out: "<0>{o1: <1>{a: 1, b: 2}, o2: <2>{a: 1, b: 2}, o3: <3>{a: 1, b: 2}, o4: <4>{a: 1, b: 2}, e: _|_((1 & <5>{a: 3}):unsupported op &(int, struct))}",
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100389 }, {
390 desc: "disjunctions",
391 in: `
392 o1: 1 | 2 | 3
393 o2: (1 | 2 | 3) & 1
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100394 o3: 2 & (1 | *2 | 3)
395 o4: (1 | *2 | 3) & (1 | 2 | *3)
396 o5: (1 | *2 | 3) & (3 | *2 | 1)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100397 o6: (1 | 2 | 3) & (3 | 1 | 2)
398 o7: (1 | 2 | 3) & (2 | 3)
399 o8: (1 | 2 | 3) & (3 | 2)
400 o9: (2 | 3) & (1 | 2 | 3)
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100401 o10: (3 | 2) & (1 | *2 | 3)
402
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100403 m1: (*1 | (*2 | 3)) & (>=2 & <=3)
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100404 m2: (*1 | (*2 | 3)) & (2 | 3)
405 m3: (*1 | *(*2 | 3)) & (2 | 3)
406 m4: (2 | 3) & (*2 | 3)
407 m5: (*2 | 3) & (2 | 3)
408
409 // (*2 | 3) & (2 | 3)
410 // (2 | 3) & (*2 | 3)
411 // 2&(*2 | 3) | 3&(*2 | 3)
412 // (*1 | (*2 | 3)) & (2 | 3)
413 // *1& (2 | 3) | (*2 | 3)&(2 | 3)
414 // *2&(2 | 3) | 3&(2 | 3)
415
416 // (2 | 3)&(*1 | (*2 | 3))
417 // 2&(*1 | (*2 | 3)) | 3&(*1 | (*2 | 3))
418 // *1&2 | (*2 | 3)&2 | *1&3 | (*2 | 3)&3
419 // (*2 | 3)&2 | (*2 | 3)&3
420 // *2 | 3
421
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100422
423 // All errors are treated the same as per the unification model.
424 i1: [1, 2][3] | "c"
425 `,
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200426 out: `<0>{o1: (1 | 2 | 3), o2: 1, o3: 2, o4: (1 | 2 | 3), o5: (1 | *2 | 3), o6: (1 | 2 | 3), o7: (2 | 3), o8: (2 | 3), o9: (2 | 3), o10: (3 | *2), m1: (*2 | 3), m2: (*2 | 3), m3: (*2 | 3), m4: (*2 | 3), m5: (*2 | 3), i1: "c"}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100427 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100428 desc: "types",
429 in: `
430 i: int
431 j: int & 3
432 s: string
433 t: "s" & string
434 e: int & string
435 e2: 1 & string
436 b: !int
437 p: +true
438 m: -false
439 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200440 out: `<0>{i: int, j: 3, s: string, t: "s", e: _|_((int & string):unsupported op &((int)*, (string)*)), e2: _|_((1 & string):unsupported op &(int, (string)*)), b: _|_(!int:unary '!' requires bool value, found (int)*), p: _|_(+true:unary '+' requires numeric value, found bool), m: _|_(-false:unary '-' requires numeric value, found bool)}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100441 }, {
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500442 desc: "comparison",
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100443 in: `
444 lss: 1 < 2
445 leq: 1 <= 1.0
446 leq: 2.0 <= 3
447 eql: 1 == 1.0
448 neq: 1.0 == 1
449 gtr: !(2 > 3)
450 geq: 2.0 >= 2
451 seq: "a" + "b" == "ab"
452 err: 2 == "s"
453 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200454 out: `<0>{lss: true, leq: true, eql: true, neq: true, gtr: true, geq: true, seq: true, err: _|_((2 == "s"):unsupported op ==(int, string))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100455 }, {
456 desc: "null",
457 in: `
458 eql: null == null
459 neq: null != null
460 unf: null & null
461
462 // errors
Marcel van Lohuizen855243e2019-02-07 18:00:55 +0100463 eq1: null == 1
464 eq2: 1 == null
465 ne1: "s" != null
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100466 call: null()
467 `,
Marcel van Lohuizen855243e2019-02-07 18:00:55 +0100468 out: `<0>{eql: true, neq: false, unf: null, eq1: false, eq2: false, ne1: true, call: _|_(null:cannot call non-function null (type null))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100469 }, {
470 desc: "self-reference cycles",
471 in: `
472 a: b - 100
473 b: a + 100
474
475 c: [c[1], c[0]]
476 `,
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200477 out: `<0>{a: _|_((<1>.b - 100):cycle detected), ` +
478 `b: _|_((<1>.a + 100):cycle detected), ` +
479 `c: [_|_(<1>.c[1]:cycle detected),_|_(<1>.c[0]:cycle detected)]}`,
Marcel van Lohuizen004bef52019-01-30 14:07:06 +0100480 }, {
481 desc: "resolved self-reference cycles",
482 in: `
483 a: b - 100
484 b: a + 100
485 b: 200
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100486
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +0200487 c: [c[1], a]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100488
Marcel van Lohuizen004bef52019-01-30 14:07:06 +0100489 s1: s2 & {a: 1}
490 s2: s3 & {b: 2}
491 s3: s1 & {c: 3}
492 `,
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +0200493 out: `<0>{a: 100, b: 200, c: [100,100], s1: <1>{a: 1, b: 2, c: 3}, s2: <2>{a: 1, b: 2, c: 3}, s3: <3>{a: 1, b: 2, c: 3}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100494 }, {
Marcel van Lohuizen89601442019-02-19 00:24:06 +0100495 desc: "resolved self-reference cycles: Issue 19",
496 in: `
497 // CUE knows how to resolve the following:
498 x: y + 100
499 y: x - 100
500 x: 200
501
502 z1: z2 + 1
503 z2: z3 + 2
504 z3: z1 - 3
505 z3: 8
506
507 // TODO: extensive tests with disjunctions.
508 `,
509 out: `<0>{x: 200, y: 100, z1: 11, z2: 10, z3: 8}`,
510 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100511 desc: "delayed constraint failure",
512 in: `
513 a: b - 100
514 b: a + 110
515 b: 200
Marcel van Lohuizen004bef52019-01-30 14:07:06 +0100516
517 x: 100
518 x: x + 1
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100519 `,
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +0100520 out: `<0>{` +
521 `a: _|_((210 & 200):cannot unify numbers 210 and 200), ` +
522 `b: _|_((210 & 200):cannot unify numbers 210 and 200), ` +
523 `x: _|_((100 & 101):cannot unify numbers 100 and 101)}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100524 // TODO: find a way to mark error in data.
525 }}
526 rewriteHelper(t, testCases, evalPartial)
527}
528
529func TestChooseFirst(t *testing.T) {
530 testCases := []testCase{{
531 desc: "pick first",
532 in: `
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100533 a: *5 | "a" | true
534 b c: *{
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100535 a: 2
536 } | {
537 a : 3
538 }
539 `,
540 out: "<0>{a: 5, b: <1>{c: <2>{a: 2}}}",
541 }, {
542 desc: "simple disambiguation conflict",
543 in: `
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100544 a: *"a" | "b"
545 b: *"b" | "a"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100546 c: a & b
547 `,
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200548 out: `<0>{a: "a", b: "b", c: _|_(("a" | "b"):more than one element remaining ("a" and "b"))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100549 }, {
Marcel van Lohuizen94b5ccc2019-01-31 07:54:24 +0100550 desc: "associativity of defaults",
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100551 in: `
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100552 a: *"a" | ("b" | "c")
553 b: (*"a" | "b") | "c"
Marcel van Lohuizen94b5ccc2019-01-31 07:54:24 +0100554 c: *"a" | (*"b" | "c")
555 x: a & b
556 y: b & c
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100557 `,
Marcel van Lohuizen94b5ccc2019-01-31 07:54:24 +0100558 out: `<0>{a: "a", b: "a", c: _|_((*"a" | *"b" | "c"):more than one default remaining ("a" and "b")), x: "a", y: _|_((*"a" | *"b" | "c"):more than one default remaining ("a" and "b"))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100559 }}
560 rewriteHelper(t, testCases, evalFull)
561}
562
563func TestResolve(t *testing.T) {
564 testCases := []testCase{{
565 in: `
566 a: b.c.d
567 b c: { d: 3 }
568 c: { c: d.d, }
569 d: { d: 2 }
570 `,
571 out: "<0>{a: 3, b: <1>{c: <2>{d: 3}}, c: <3>{c: 2}, d: <4>{d: 2}}",
572 }, {
573 in: `
574 a: _
575 b: a
576 a: { d: 1, d: _ }
577 b: _
578 `,
579 out: `<0>{a: <1>{d: 1}, b: <2>{d: 1}}`,
580 }, {
581 desc: "JSON",
582 in: `
583 "a": 3
584 b: a
585 o: { "a\nb": 2 } // TODO: use $ for root?
586 c: o["a\nb"]
587 `,
588 out: `<0>{a: 3, b: 3, o: <1>{"a\nb": 2}, c: 2}`,
589 }, {
590 desc: "arithmetic",
591 in: `
Marcel van Lohuizen0a7717d2019-02-13 17:36:32 +0400592 v1: 1.0T/2.0
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100593 v2: 2.0 == 2
Marcel van Lohuizen0a7717d2019-02-13 17:36:32 +0400594 n1: 1
595 v5: 2.0 / n1
596 e1: 2.0 % (3&int)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100597 e2: int & 4.0/2.0
598 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200599 out: `<0>{v1: 5e+11, v2: true, n1: 1, v5: 2, e1: 2.0, e2: _|_((int & 2):unsupported op &((int)*, float))}`,
Marcel van Lohuizen66db9202018-12-17 19:02:08 +0100600 }, {
Marcel van Lohuizen855243e2019-02-07 18:00:55 +0100601 desc: "inequality",
602 in: `
603 a: 1 != 2
604 b: 1 != null
605 c: true == null
606 d: null != {}
607 e: null == []
608 f: 0 == 0.0 // types are unified first TODO: make this consistent
609 `,
610 out: `<0>{a: true, b: true, c: false, d: true, e: false, f: true}`,
611 }, {
Marcel van Lohuizenb9b62d32019-03-14 23:50:15 +0100612 desc: "attributes",
613 in: `
614 a: { foo: 1 @foo() @baz(1) }
615 b: { foo: 1 @bar() @foo() }
616 c: a & b
617
618 e: a & { foo: 1 @foo(other) }
619 `,
620 out: `<0>{a: <1>{foo: 1 @baz(1) @foo()}, ` +
621 `b: <2>{foo: 1 @bar() @foo()}, ` +
622 `c: <3>{foo: 1 @bar() @baz(1) @foo()}, ` +
623 `e: _|_((<4>.a & <5>{foo: 1 @foo(other)}):conflicting attributes for key "foo")}`,
624 }, {
Marcel van Lohuizen08a0ef22019-03-28 09:12:19 +0100625 desc: "optional fields",
626 in: `
627 a: { foo?: string }
628 b: { foo: "foo" }
629 c: a & b
630 d: a & { "foo"?: "bar" }
631
632 g1: 1
633 "g\(1)"?: 1
634 "g\(2)"?: 2
635 `,
636 out: `<0>{a: <1>{foo?: string}, ` +
637 `b: <2>{foo: "foo"}, ` +
638 `c: <3>{foo: "foo"}, ` +
639 `d: <4>{foo?: "bar"}, ` +
640 `g1: 1, ` +
641 `g2?: 2}`,
642 }, {
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100643 desc: "bounds",
644 in: `
645 i1: >1 & 5
646 i2: (>=0 & <=10) & 5
647 i3: !=null & []
648 i4: !=2 & !=4
649
650
651 s1: >=0 & <=10 & !=1 // no simplification
652 s2: >=0 & <=10 & !=11 // >=0 & <=10
653 s3: >5 & !=5 // >5
654 s4: <10 & !=10 // <10
655 s5: !=2 & !=2
656
Marcel van Lohuizen706e69c2019-02-11 18:21:14 +0100657 // TODO: could change inequality
658 s6: !=2 & >=2
659 s7: >=2 & !=2
660
661 s8: !=5 & >5
662
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100663 s10: >=0 & <=10 & <12 & >1 // >1 & <=10
664 s11: >0 & >=0 & <=12 & <12 // >0 & <12
665
666 s20: >=10 & <=10 // 10
667
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200668 s22: >5 & <=6 // no simplification
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100669 s22a: >5 & (<=6 & int) // 6
670 s22b: (int & >5) & <=6 // 6
671 s22c: >=5 & (<6 & int) // 5
672 s22d: (int & >=5) & <6 // 5
673 s22e: (>=5 & <6) & int // 5
674 s22f: int & (>=5 & <6) // 5
675
676 s23: >0 & <2 // no simplification
677 s23a: (>0 & <2) & int // int & 1
678 s23b: int & (>0 & <2) // int & 1
679 s23c: (int & >0) & <2 // int & 1
680 s23d: >0 & (int & <2) // int & 1
681 s23e: >0.0 & <2.0 // no simplification
682
683 s30: >0 & int
684
685 e1: null & !=null
686 e2: !=null & null
687 e3: >1 & 1
688 e4: <0 & 0
689 e5: >1 & <0
690 e6: >11 & <11
691 e7: >=11 & <11
692 e8: >11 & <=11
693 e9: >"a" & <1
694 `,
695 out: `<0>{i1: 5, i2: 5, i3: [], i4: (!=2 & !=4), ` +
696
697 `s1: (>=0 & <=10 & !=1), ` +
698 `s2: (>=0 & <=10), ` +
699 `s3: >5, ` +
700 `s4: <10, ` +
701 `s5: !=2, ` +
702
Marcel van Lohuizen706e69c2019-02-11 18:21:14 +0100703 `s6: (!=2 & >=2), ` +
704 `s7: (>=2 & !=2), ` +
705
706 `s8: >5, ` +
707
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100708 `s10: (<=10 & >1), ` +
709 `s11: (>0 & <12), ` +
710
711 `s20: 10, ` +
712
713 `s22: (>5 & <=6), ` +
714 `s22a: 6, ` +
715 `s22b: 6, ` +
716 `s22c: 5, ` +
717 `s22d: 5, ` +
718 `s22e: 5, ` +
719 `s22f: 5, ` +
720
721 `s23: (>0 & <2), ` +
722 `s23a: 1, ` +
723 `s23b: 1, ` +
724 `s23c: 1, ` +
725 `s23d: 1, ` +
726 `s23e: (>0.0 & <2.0), ` +
727
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200728 `s30: int & >0, ` +
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100729
730 `e1: _|_((!=null & null):null excluded by !=null), ` +
731 `e2: _|_((!=null & null):null excluded by !=null), ` +
732 `e3: _|_((>1 & 1):1 not within bound >1), ` +
733 `e4: _|_((<0 & 0):0 not within bound <0), ` +
734 `e5: _|_(incompatible bounds >1 and <0), ` +
735 `e6: _|_(incompatible bounds >11 and <11), ` +
736 `e7: _|_(incompatible bounds >=11 and <11), ` +
737 `e8: _|_(incompatible bounds >11 and <=11), ` +
738 `e9: _|_((>"a" & <1):unsupported op &((string)*, (number)*))}`,
739 }, {
Marcel van Lohuizen66db9202018-12-17 19:02:08 +0100740 desc: "null coalescing",
741 in: `
742 a: null
743 b: a.x | "b"
744 c: a["x"] | "c"
745 `,
746 out: `<1>{a: null, b: "b", c: "c"}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100747 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100748 desc: "reference across tuples and back",
749 // Tests that it is okay to partially evaluate structs.
750 in: `
751 a: { c: b.e, d: b.f }
752 b: { e: 3, f: a.c }
753 `,
754 out: "<0>{a: <1>{c: 3, d: 3}, b: <2>{e: 3, f: 3}}",
755 }, {
756 desc: "index",
757 in: `
758 a: [2][0]
759 b: {foo:"bar"}["foo"]
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100760 c: (*l|{"3":3})["3"]
761 d: (*[]|[1])[0]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100762 l: []
763 e1: [2][""]
764 e2: 2[2]
765 e3: [][true]
766 e4: [1,2,3][3]
767 e5: [1,2,3][-1]
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100768 e6: (*[]|{})[1]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100769 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200770 out: `<0>{a: 2, b: "bar", c: _|_("3":invalid list index "3" (type string)), l: [], d: _|_([]:index 0 out of bounds), e1: _|_("":invalid list index "" (type string)), e2: _|_(2:invalid operation: 2[2] (type int does not support indexing)), e3: _|_(true:invalid list index true (type bool)), e4: _|_([1,2,3]:index 3 out of bounds), e5: _|_(-1:invalid list index -1 (index must be non-negative)), e6: _|_([]:index 1 out of bounds)}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100771 }, {
772 desc: "string index",
773 in: `
774 a0: "abc"[0]
775 a1: "abc"[1]
776 a2: "abc"[2]
777 a3: "abc"[3]
778 a4: "abc"[-1]
779
780 b: "zoëven"[2]
781 `,
782 out: `<0>{a0: "a", a1: "b", a2: "c", a3: _|_("abc":index 3 out of bounds), a4: _|_(-1:invalid string index -1 (index must be non-negative)), b: "ë"}`,
783 }, {
784 desc: "disjunctions of lists",
785 in: `
786 l: [ int, int ] | [ string, string ]
787
788 l1: [ "a", "b" ]
789 l2: l & [ "c", "d" ]
790 `,
791 out: `<0>{l: ([int,int] | [string,string]), l1: ["a","b"], l2: ["c","d"]}`,
792 }, {
793 desc: "slice",
794 in: `
795 a: [2][0:0]
796 b: [0][1:1]
797 e1: [][1:1]
798 e2: [0][-1:0]
799 e3: [0][1:0]
800 e4: [0][1:2]
801 e5: 4[1:2]
802 e6: [2]["":]
803 e7: [2][:"9"]
804
805 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200806 out: `<0>{a: [], b: [], e1: _|_(1:slice bounds out of range), e2: _|_([0]:negative slice index), e3: _|_([0]:invalid slice index: 1 > 0), e4: _|_(2:slice bounds out of range), e5: _|_(4:cannot slice 4 (type int)), e6: _|_("":invalid slice index "" (type string)), e7: _|_("9":invalid slice index "9" (type string))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100807 }, {
808 desc: "string slice",
809 in: `
810 a0: ""[0:0]
811 a1: ""[:]
812 a2: ""[0:]
813 a3: ""[:0]
814 b0: "abc"[0:0]
815 b1: "abc"[0:1]
816 b2: "abc"[0:2]
817 b3: "abc"[0:3]
818 b4: "abc"[3:3]
819 b5: "abc"[1:]
820 b6: "abc"[:2]
821
822 // TODO: supported extended graphemes, instead of just runes.
823 u: "Spaß"[3:4]
824 `,
825 out: `<0>{a0: "", a1: "", a2: "", a3: "", b0: "", b1: "a", b2: "ab", b3: "abc", b4: "", b5: "bc", b6: "ab", u: "ß"}`,
826 }, {
827 desc: "list types",
828 in: `
829 l0: 3*[int]
830 l0: [1, 2, 3]
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500831 l2: [...{ a: int }]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100832 l2: [{a: 1}, {a: 2, b: 3}]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100833
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100834 // TODO: work out a decent way to specify length ranges of lists.
835 // l3: <=10*[int]
836 // l3: [1, 2, 3, ...]
837
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500838 s1: (6*[int])[2:3]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100839 s2: [0,2,3][1:2]
840
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500841 i1: (6*[int])[2]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100842 i2: [0,2,3][2]
843
844 t0: [...{a: 8}]
845 t0: [{}]
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500846 t1: [...]
847 t1: [...int]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100848
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500849 e0: 2*[{}]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100850 e0: [{}]
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500851 e1: [...int]
852 e1: [...float]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100853 `,
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500854 out: `<0>{` +
855 `l0: [1,2,3], ` +
856 `l2: [<1>{a: 1},<2>{a: 2, b: 3}], ` +
857 `s1: [int], ` +
858 `s2: [2], ` +
859 `i1: int, ` +
860 `i2: 3, ` +
861 `t0: [<3>{a: 8}], ` +
862 `t1: [, ...int], ` +
863 `e0: _|_(([<4>{},<4>{}] & [<5>{}]):incompatible list lengths: cannot unify numbers 2 and 1), ` +
864 `e1: _|_(([, ...int] & [, ...float]):incompatible list types: unsupported op &((int)*, (float)*): )` +
865 `}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100866 }, {
Marcel van Lohuizenb134a502019-05-06 11:33:05 +0200867 // TODO: consider removing list arithmetic altogether. It is no longer
868 // needed to indicate the allowed capacity of a list and that didn't
869 // work anyway.
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100870 desc: "list arithmetic",
871 in: `
872 l0: 3*[1, 2, 3]
873 l1: 0*[1, 2, 3]
874 l2: 10*[]
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100875 l3: <=2*[]
876 l4: <=2*[int]
877 l5: <=2*(int*[int])
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500878 l6: 3*[...int]
879 l7: 3*[1, ...int]
880 l8: 3*[1, 2, ...int]
Marcel van Lohuizen09d814d2019-02-22 19:14:33 +0100881
882 s0: [] + []
883 s1: [1] + []
884 s2: [] + [2]
885 s3: [1] + [2]
886 s4: [1,2] + []
887 s5: [] + [1,2]
888 s6: [1] + [1,2]
889 s7: [1,2] + [1]
890 s8: [1,2] + [1,2]
891 s9: [] + [...]
892 s10: [1] + [...]
893 s11: [] + [2, ...]
894 s12: [1] + [2, ...]
895 s13: [1,2] + [...]
896 s14: [] + [1,2, ...]
897 s15: [1] + [1,2, ...]
898 s16: [1,2] + [1, ...]
899 s17: [1,2] + [1,2, ...]
900
901 s18: [...] + []
902 s19: [1, ...] + []
903 s20: [...] + [2]
904 s21: [1, ...] + [2]
905 s22: [1,2, ...] + []
906 s23: [...] + [1,2]
907 s24: [1, ...] + [1,2]
908 s25: [1,2, ...] + [1]
909 s26: [1,2, ...] + [1,2]
910 s27: [...] + [...]
911 s28: [1, ...] + [...]
912 s29: [...] + [2, ...]
913 s30: [1, ...] + [2, ...]
914 s31: [1,2, ...] + [...]
915 s32: [...] + [1,2, ...]
916 s33: [1, ...] + [1,2, ...]
917 s34: [1,2, ...] + [1, ...]
918 s35: [1,2, ...] + [1,2, ...]
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500919 `,
920 out: `<0>{l0: [1,2,3,1,2,3,1,2,3], ` +
921 `l1: [], ` +
922 `l2: [], ` +
923 `l3: (<=2 * []), ` +
924 `l4: (<=2 * [int]), ` +
925 `l5: (<=2 * (int * [int])), ` +
Marcel van Lohuizenb134a502019-05-06 11:33:05 +0200926 `l6: [], ` +
927 `l7: [1,1,1], ` +
928 `l8: [1,2,1,2,1,2], ` +
Marcel van Lohuizen09d814d2019-02-22 19:14:33 +0100929
930 `s0: [], ` +
931 `s1: [1], ` +
932 `s2: [2], ` +
933 `s3: [1,2], ` +
934 `s4: [1,2], ` +
935 `s5: [1,2], ` +
936 `s6: [1,1,2], ` +
937 `s7: [1,2,1], ` +
938 `s8: [1,2,1,2], ` +
Marcel van Lohuizenb134a502019-05-06 11:33:05 +0200939 `s9: [], ` +
940 `s10: [1], ` +
941 `s11: [2], ` +
942 `s12: [1,2], ` +
943 `s13: [1,2], ` +
944 `s14: [1,2], ` +
945 `s15: [1,1,2], ` +
946 `s16: [1,2,1], ` +
947 `s17: [1,2,1,2], ` +
Marcel van Lohuizen09d814d2019-02-22 19:14:33 +0100948
949 `s18: [], ` +
950 `s19: [1], ` +
951 `s20: [2], ` +
952 `s21: [1,2], ` +
953 `s22: [1,2], ` +
954 `s23: [1,2], ` +
955 `s24: [1,1,2], ` +
956 `s25: [1,2,1], ` +
957 `s26: [1,2,1,2], ` +
Marcel van Lohuizenb134a502019-05-06 11:33:05 +0200958 `s27: [], ` +
959 `s28: [1], ` +
960 `s29: [2], ` +
961 `s30: [1,2], ` +
962 `s31: [1,2], ` +
963 `s32: [1,2], ` +
964 `s33: [1,1,2], ` +
965 `s34: [1,2,1], ` +
966 `s35: [1,2,1,2]` +
Marcel van Lohuizen09d814d2019-02-22 19:14:33 +0100967
Jonathan Amsterdam0500c312019-02-16 18:04:09 -0500968 `}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100969 }, {
Marcel van Lohuizen0aeeeaf2019-02-22 19:50:18 +0100970 desc: "list equality",
971 in: `
972 eq0: [] == []
973 eq1: [...] == []
974 eq2: [] == [...]
975 eq3: [...] == [...]
976
977 eq4: [1] == [1]
978 eq5: [1, ...] == [1]
979 eq6: [1] == [1, ...]
980 eq7: [1, ...] == [1, ...]
981
982 eq8: [1, 2] == [1, 2]
983 eq9: [1, 2, ...] == [1, 2]
984 eq10: [1, 2] == [1, 2, ...]
985 eq11: [1, 2, ...] == [1, 2, ...]
986
987 ne0: [] != []
988 ne1: [...] != []
989 ne2: [] != [...]
990 ne3: [...] != [...]
991
992 ne4: [1] != [1]
993 ne5: [1, ...] != [1]
994 ne6: [1] != [1, ...]
995 ne7: [1, ...] != [1, ...]
996
997 ne8: [1, 2] != [1, 2]
998 ne9: [1, 2, ...] != [1, 2]
999 ne10: [1, 2] != [1, 2, ...]
1000 ne11: [1, 2, ...] != [1, 2, ...]
1001
1002 feq0: [] == [1]
1003 feq1: [...] == [1]
1004 feq2: [] == [1, ...]
1005 feq3: [...] == [1, ...]
1006
1007 feq4: [1] == []
1008 feq5: [1, ...] == []
1009 feq6: [1] == [...]
1010 feq7: [1, ...] == [...]
1011
1012 feq8: [1, 2] == [1]
1013 feq9: [1, ...] == [1, 2]
1014 feq10: [1, 2] == [1, ...]
1015 feq11: [1, ...] == [1, 2, ...]
1016
1017 fne0: [] != [1]
1018 fne1: [...] != [1]
1019 fne2: [] != [1, ...]
1020 fne3: [1, ...] != [1, ...]
1021
1022 fne4: [1] != []
1023 fne5: [1, ...] != []
1024 fne6: [1] != [...]
1025 fne7: [1, ...] != [...]
1026
1027 fne8: [1, 2] != [1]
1028 fne9: [1, ...] != [1, 2]
1029 fne10: [1, 2] != [1, ...]
1030 fne11: [1, ...] != [1, 2, ...]
1031 `,
1032 out: `<0>{` +
1033 `eq0: true, eq1: true, eq2: true, eq3: true, eq4: true, eq5: true, eq6: true, eq7: true, eq8: true, eq9: true, eq10: true, eq11: true, ` +
1034 `ne0: true, ne1: true, ne2: true, ne3: true, ne4: false, ne5: false, ne6: false, ne7: false, ne8: false, ne9: false, ne10: false, ne11: false, ` +
1035 `feq0: false, feq1: false, feq2: false, feq3: false, feq4: false, feq5: false, feq6: false, feq7: false, feq8: false, feq9: false, feq10: false, feq11: false, ` +
1036 `fne0: false, fne1: false, fne2: false, fne3: false, fne4: false, fne5: false, fne6: false, fne7: false, fne8: false, fne9: false, fne10: false, fne11: false}`,
1037 }, {
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +02001038 desc: "list unification",
1039 in: `
1040 a: { l: ["foo", v], v: l[1] }
1041 b: a & { l: [_, "bar"] }
1042 `,
1043 out: `<0>{` +
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001044 `a: <1>{l: ["foo",_|_(<2>.v:cycle detected)], ` +
1045 `v: _|_(<2>.l[1]:cycle detected)}, ` +
1046 `b: <3>{l: ["foo","bar"], v: "bar"}}`,
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +02001047 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001048 desc: "correct error messages",
1049 // Tests that it is okay to partially evaluate structs.
1050 in: `
1051 a: "a" & 1
1052 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001053 out: `<0>{a: _|_(("a" & 1):unsupported op &(string, int))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001054 }, {
1055 desc: "structs",
1056 in: `
1057 a: t & { c: 5 } // {c:5,d:15}
1058 b: ti & { c: 7 } // {c:7,d:21}
1059 t: { c: number, d: c * 3 } // {c:number,d:number*3}
1060 ti: t & { c: int }
1061 `,
1062 out: `<0>{a: <1>{c: 5, d: 15}, t: <2>{c: number, d: (<3>.c * 3)}, b: <4>{c: 7, d: 21}, ti: <5>{c: int, d: (<6>.c * 3)}}`,
1063 }, {
1064 desc: "reference to root",
1065 in: `
1066 a: { b: int }
1067 c: a & {
1068 b: 100
1069 d: a.b + 3 // do not resolve as c != a.
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001070 }
1071 x: {
1072 b: int
1073 c: b + 5
1074 }
1075 y: x & {
1076 b: 100
1077 // c should resolve to 105
1078 }
1079 v: {
1080 b: int
1081 c: v.b + 5 // reference starting from copied node.
1082 }
1083 w: v & { b: 100 }
1084 wp: v & { b: 100 }
1085 `,
1086 out: `<0>{a: <1>{b: int}, c: <2>{b: 100, d: (<3>.a.b + 3)}, x: <4>{b: int, c: (<5>.b + 5)}, y: <6>{b: 100, c: 105}, v: <7>{b: int, c: (<8>.b + 5)}, w: <9>{b: 100, c: 105}, wp: <10>{b: 100, c: 105}}`,
1087 }, {
1088 desc: "references from template to concrete",
1089 in: `
1090 res: [t]
1091 t <X>: {
1092 a: c + b.str
1093 b str: string
1094 c: "X"
1095 }
1096 t x: { b str: "DDDD" }
1097 `,
1098 out: `<0>{res: [<1>{<>: <2>(X: string)-><3>{a: (<3>.c + <3>.b.str), c: "X", b: <4>{str: string}}, x: <5>{a: "XDDDD", c: "X", b: <6>{str: "DDDD"}}}], t: <7>{<>: <2>(X: string)-><3>{a: (<3>.c + <3>.b.str), c: "X", b: <4>{str: string}}, x: <8>{a: "XDDDD", c: "X", b: <9>{str: "DDDD"}}}}`,
1099 }, {
1100 desc: "interpolation",
1101 in: `
1102 a: "\(4)"
1103 b: "one \(a) two \( a + c )"
1104 c: "one"
1105 d: "\(r)"
1106 u: "\(_)"
1107 r: _
1108 e: "\([])"`,
1109 out: `<0>{a: "4", b: "one 4 two 4one", c: "one", d: ""+<1>.r+"", r: _, u: ""+_+"", e: _|_([]:expression in interpolation must evaluate to a number kind or string (found list))}`,
1110 }, {
Marcel van Lohuizen369e4232019-02-15 10:59:29 +04001111 desc: "multiline interpolation",
1112 in: `
1113 a1: """
1114 before
1115 \(4)
1116 after
1117 """
1118 a2: """
1119 before
1120 \(4)
1121
1122 """
1123 a3: """
1124
1125 \(4)
1126 after
1127 """
1128 a4: """
1129
1130 \(4)
1131
1132 """
1133 m1: """
1134 before
1135 \(
1136 4)
1137 after
1138 """
1139 m2: """
1140 before
1141 \(
1142 4)
1143
1144 """
1145 m3: """
1146
1147 \(
1148
1149 4)
1150 after
1151 """
1152 m4: """
1153
1154 \(
1155 4)
1156
1157 """
1158 `,
1159 out: `<0>{` +
1160 `a1: "before\n4\nafter", a2: "before\n4\n", a3: "\n4\nafter", a4: "\n4\n", ` +
1161 `m1: "before\n4\nafter", m2: "before\n4\n", m3: "\n4\nafter", m4: "\n4\n"` +
1162 `}`,
1163 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001164 desc: "diamond-shaped constraints",
1165 in: `
1166 S: {
1167 A: {
1168 a: 1,
1169 },
1170 B: A & {
1171 b: 2,
1172 }
1173 },
1174 T: S & { // S == { A: { a:1 }, B: { a:1, b:2 } }
1175 A: {
1176 c: 3,
1177 },
1178 B: { // S.B & A
1179 d: 4, // Combines constraints S.A, S.B, T.A, and T.B
1180 }
1181 }`,
1182 out: "<0>{S: <1>{A: <2>{a: 1}, B: <3>{a: 1, b: 2}}, T: <4>{A: <5>{a: 1, c: 3}, B: <6>{a: 1, b: 2, c: 3, d: 4}}}",
1183 }, {
1184 desc: "field templates",
1185 in: `
1186 a: {
1187 <name>: int
1188 k: 1
1189 }
1190 b: {
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001191 <x>: { x: 0, y: *1 | int }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001192 v: {}
1193 w: { x: 0 }
1194 }
1195 b: { <y>: {} } // TODO: allow different name
1196 c: {
1197 <Name>: { name: Name, y: 1 }
1198 foo: {}
1199 bar: _
1200 }
1201 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001202 out: `<0>{a: <1>{<>: <2>(name: string)->int, k: 1}, b: <3>{<>: <4>(x: string)->(<5>{x: 0, y: (*1 | int)} & <6>{}), v: <7>{x: 0, y: (*1 | int)}, w: <8>{x: 0, y: (*1 | int)}}, c: <9>{<>: <10>(Name: string)-><11>{name: <10>.Name, y: 1}, foo: <12>{name: "foo", y: 1}, bar: <13>{name: "bar", y: 1}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001203 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001204 desc: "range unification",
1205 in: `
1206 // with concrete values
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001207 a1: >=1 & <=5 & 3
1208 a2: >=1 & <=5 & 1
1209 a3: >=1 & <=5 & 5
1210 a4: >=1 & <=5 & 6
1211 a5: >=1 & <=5 & 0
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001212
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001213 a6: 3 & >=1 & <=5
1214 a7: 1 & >=1 & <=5
1215 a8: 5 & >=1 & <=5
1216 a9: 6 & >=1 & <=5
1217 a10: 0 & >=1 & <=5
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001218
1219 // with ranges
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001220 b1: >=1 & <=5 & >=1 & <=5
1221 b2: >=1 & <=5 & >=1 & <=1
1222 b3: >=1 & <=5 & >=5 & <=5
1223 b4: >=1 & <=5 & >=2 & <=3
1224 b5: >=1 & <=5 & >=3 & <=9
1225 b6: >=1 & <=5 & >=5 & <=9
1226 b7: >=1 & <=5 & >=6 & <=9
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001227
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001228 b8: >=1 & <=5 & >=1 & <=5
1229 b9: >=1 & <=1 & >=1 & <=5
1230 b10: >=5 & <=5 & >=1 & <=5
1231 b11: >=2 & <=3 & >=1 & <=5
1232 b12: >=3 & <=9 & >=1 & <=5
1233 b13: >=5 & <=9 & >=1 & <=5
1234 b14: >=6 & <=9 & >=1 & <=5
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001235
1236 // ranges with more general types
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001237 c1: int & >=1 & <=5
1238 c2: >=1 & <=5 & int
1239 c3: string & >=1 & <=5
1240 c4: >=1 & <=5 & string
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001241
1242 // other types
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001243 s1: >="d" & <="z" & "e"
1244 s2: >="d" & <="z" & "ee"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001245
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001246 n1: number & >=1 & <=2
1247 n2: int & >=1.1 & <=1.3
1248 n3: >=1.0 & <=3.0 & 2
1249 n4: >=0.0 & <=0.1 & 0.09999
1250 n5: >=1 & <=5 & 2.5
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001251 `,
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001252 out: `<0>{` +
1253 `a1: 3, ` +
1254 `a2: 1, ` +
1255 `a3: 5, ` +
1256 `a4: _|_((<=5 & 6):6 not within bound <=5), ` +
1257 `a5: _|_((>=1 & 0):0 not within bound >=1), ` +
1258 `a6: 3, ` +
1259 `a7: 1, ` +
1260 `a8: 5, ` +
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001261
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001262 // TODO: improve error
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001263 `a9: _|_((<=5 & 6):6 not within bound <=5), ` +
1264 `a10: _|_((>=1 & 0):0 not within bound >=1), ` +
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001265
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001266 `b1: (>=1 & <=5), ` +
1267 `b2: 1, ` +
1268 `b3: 5, ` +
1269 `b4: (>=2 & <=3), ` +
1270 `b5: (>=3 & <=5), ` +
1271 `b6: 5, ` +
1272 `b7: _|_(incompatible bounds >=6 and <=5), ` +
1273 `b8: (>=1 & <=5), ` +
1274 `b9: 1, ` +
1275 `b10: 5, ` +
1276 `b11: (>=2 & <=3), ` +
1277 `b12: (>=3 & <=5), ` +
1278 `b13: 5, ` +
1279 `b14: _|_(incompatible bounds >=6 and <=5), ` +
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001280 `c1: (int & >=1 & <=5), ` +
1281 `c2: (<=5 & int & >=1), ` +
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001282 `c3: _|_((string & >=1):unsupported op &((string)*, (number)*)), ` +
1283 `c4: _|_(((>=1 & <=5) & string):unsupported op &((number)*, (string)*)), ` +
1284 `s1: "e", ` +
1285 `s2: "ee", ` +
1286 `n1: (>=1 & <=2), ` +
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001287 `n2: (int & >=1.1 & <=1.3), ` +
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001288 `n3: 2, ` +
1289 `n4: 0.09999, ` +
1290 `n5: 2.5}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001291 }, {
1292 desc: "predefined ranges",
1293 in: `
1294 k1: int8
1295 k1: 44
1296
1297 k2: int64
1298 k2: -8_000_000_000
1299
1300 e1: int16
1301 e1: 100_000
1302 `,
1303 out: `<0>{k1: 44, k2: -8000000000, ` +
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001304 `e1: _|_((int & <=32767 & 100000):100000 not within bound int & <=32767)}`,
Marcel van Lohuizen66db9202018-12-17 19:02:08 +01001305 }, {
1306 desc: "field comprehensions",
1307 in: `
1308 obj foo a: "bar"
1309 obj <Name>: {
Marcel van Lohuizene7e8f0d2019-02-06 12:29:58 +01001310 a: *"dummy" | string
Marcel van Lohuizen66db9202018-12-17 19:02:08 +01001311 sub as: a if true
1312 }
1313 `,
Marcel van Lohuizene7e8f0d2019-02-06 12:29:58 +01001314 out: `<0>{obj: <1>{<>: <2>(Name: string)-><3>{a: (*"dummy" | string) if true yield ("sub"): <4>{as: <3>.a}}, ` +
Marcel van Lohuizen66db9202018-12-17 19:02:08 +01001315 `foo: <5>{a: "bar", sub: <6>{as: "bar"}}}}`,
Marcel van Lohuizen004bef52019-01-30 14:07:06 +01001316 }, {
Marcel van Lohuizena460fe82019-04-26 10:20:51 +02001317 desc: "builtins",
1318 in: `
1319 a1: {
1320 a: and([b, c])
1321 b: =~"oo"
1322 c: =~"fo"
1323 }
1324 a2: a1 & { a: "foo" }
1325 a3: a1 & { a: "bar" }
1326
1327 o1: {
1328 a: or([b, c])
1329 b: string
1330 c: "bar"
1331 }
1332 o2: o1 & { a: "foo" }
1333 o3: o1 & { a: "foo", b: "baz" }
1334 `,
1335 out: `<0>{` +
1336 `a1: <1>{a: (=~"oo" & =~"fo"), b: =~"oo", c: =~"fo"}, ` +
1337 `a2: <2>{a: "foo", b: =~"oo", c: =~"fo"}, ` +
1338 `a3: <3>{a: _|_((=~"oo" & "bar"):"bar" does not match =~"oo"), b: =~"oo", c: =~"fo"}, ` +
1339 `o1: <4>{a: string, b: string, c: "bar"}, ` +
1340 `o2: <5>{a: "foo", b: string, c: "bar"}, ` +
1341 `o3: <6>{a: _|_((builtin:or ([<7>.b,<7>.c]) & "foo"):empty disjunction: failed to unify: baz != foo), b: "baz", c: "bar"}}`,
1342 }, {
Marcel van Lohuizen004bef52019-01-30 14:07:06 +01001343 desc: "self-reference cycles conflicts with strings",
1344 in: `
1345 a: {
1346 x: y+"?"
1347 y: x+"!"
1348 }
1349 a x: "hey"
1350 `,
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001351 out: `<0>{a: <1>{x: _|_(("hey!?" & "hey"):failed to unify: hey!? != hey), y: "hey!"}}`,
Marcel van Lohuizen004bef52019-01-30 14:07:06 +01001352 }, {
1353 desc: "resolved self-reference cycles with disjunctions",
1354 in: `
1355 a: b&{x:1} | {y:1} // {x:1,y:3,z:2} | {y:1}
1356 b: {x:2} | c&{z:2} // {x:2} | {x:1,y:3,z:2}
1357 c: a&{y:3} | {z:3} // {x:1,y:3,z:2} | {z:3}
1358 `,
1359 out: `<0>{a: (<1>{x: 1, y: 3, z: 2} | <2>{y: 1}), b: (<3>{x: 2} | <4>{x: 1, y: 3, z: 2}), c: (<5>{x: 1, y: 3, z: 2} | <6>{z: 3})}`,
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001360 }, {
1361 // We take a very conservative stance on delaying arithmetic
1362 // expressions within disjunctions. It should remain resolvable, though,
1363 // once the user specifies one.
1364 desc: "resolved self-reference cycles with disjunction",
1365 in: `
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001366 // The second disjunct in xa1 is not resolvable and can be
1367 // eliminated:
1368 // xa4 & 9
1369 // (xa2 + 2) & 9
1370 // ((xa3 + 2) + 2) & 9
1371 // (((6 & xa1-2) + 2) + 2) & 9
1372 // ((6 + 2) + 2) & 9 // 6 == xa1-2
1373 // 10 & 9 => _|_
1374 // The remaining values resolve.
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001375 xa1: (xa2 & 8) | (xa4 & 9)
1376 xa2: xa3 + 2
1377 xa3: 6 & xa1-2
1378 xa4: xa2 + 2
1379
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001380 // The second disjunct in xb4 can be eliminated as both disjuncts
1381 // of xb3 result in an incompatible sum when substituted.
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001382 xb1: (xb2 & 8) | (xb4 & 9)
1383 xb2: xb3 + 2
1384 xb3: (6 & (xb1-2)) | (xb4 & 9)
1385 xb4: xb2 + 2
1386
1387 // Another variant with more disjunctions. xc1 remains with two
1388 // possibilities. Technically, only the first value is valid.
1389 // However, to fully determine that, all options of the remaining
1390 // disjunction will have to be evaluated algebraically, which is
1391 // not done.
1392 xc1: xc2 & 8 | xc4 & 9 | xc5 & 9
1393 xc2: xc3 + 2
1394 xc3: 6 & xc1-2
1395 xc4: xc2 + 1
1396 xc5: xc2 + 2
1397
1398 // The above is resolved by setting xd1 explicitly.
1399 xd1: xd2 & 8 | xd4 & 9 | xd5 & 9
1400 xd2: xd3 + 2
1401 xd3: 6 & xd1-2
1402 xd4: xd2 + 1
1403 xd5: xd2 + 2
1404 xd1: 8
1405
1406 // The above is resolved by setting xd1 explicitly to the wrong
1407 // value, resulting in an error.
1408 xe1: xe2 & 8 | xe4 & 9 | xe5 & 9
1409 xe2: xe3 + 2
1410 xe3: 6 & xe1-2
1411 xe4: xe2 + 1
1412 xe5: xe2 + 2
1413 xe1: 9
1414
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001415 // Only one solution.
1416 xf1: xf2 & 8 | xf4 & 9
1417 xf2: xf3 + 2
1418 xf3: 6 & xf1-2 | xf4 & 9
1419 xf4: xf2 + 2
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001420
1421 z1: z2 + 1 | z3 + 5
1422 z2: z3 + 2
1423 z3: z1 - 3
1424 z3: 8
1425 `,
1426 out: `<0>{` +
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001427 `xa1: 8, ` +
1428 `xa2: 8, ` +
1429 `xa4: 10, ` +
1430 `xa3: 6, ` +
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001431
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001432 `xb1: 8, ` +
1433 `xb2: 8, ` +
1434 `xb4: 10, ` +
1435 `xb3: 6, ` +
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001436
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001437 `xc1: ((<1>.xc2 & 8) | (<1>.xc4 & 9) | (<1>.xc5 & 9)), ` +
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001438 `xc2: (<1>.xc3 + 2), ` +
1439 `xc4: (<1>.xc2 + 1), ` +
1440 `xc5: (<1>.xc2 + 2), ` +
1441 `xc3: (6 & (<1>.xc1 - 2)), ` +
1442
1443 `xd1: 8, ` +
1444 `xd2: 8, ` +
1445 `xd4: 9, ` +
1446 `xd5: 10, ` +
1447 `xd3: 6, ` +
1448
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001449 `xe1: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001450 `xe2: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
1451 `xe4: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
1452 `xe5: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
1453 `xe3: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
1454
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001455 `xf1: 8, ` +
1456 `xf2: 8, ` +
1457 `xf4: 10, ` +
1458 `xf3: 6, ` +
1459
1460 `z1: ((<1>.z2 + 1) | (<1>.z3 + 5)), ` +
1461 `z2: (<1>.z3 + 2), ` +
1462 `z3: ((<1>.z1 - 3) & 8)}`,
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001463 }, {
1464 // Defaults should not alter the result of the above disjunctions.
1465 // The results may differ, but errors and resolution should be roughly
1466 // the same.
1467 desc: "resolved self-reference cycles with disjunction with defaults",
1468 in: `
1469 // The disjunction in xa could be resolved, but as disjunctions
1470 // are not resolved for expression, it remains unresolved.
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001471 xa1: (xa2 & 8) | *(xa4 & 9)
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001472 xa2: xa3 + 2
1473 xa3: 6 & xa1-2
1474 xa4: xa2 + 2
1475
1476 // As xb3 is a disjunction, xb2 cannot be resolved and evaluating
1477 // the cycle completely is broken. However, it is not an error
1478 // as the user might still resolve the disjunction.
1479 xb1: *(xb2 & 8) | (xb4 & 9)
1480 xb2: xb3 + 2
1481 xb3: *(6 & (xb1-2)) | (xb4 & 9)
1482 xb4: xb2 + 2
1483
1484 // Another variant with more disjunctions. xc1 remains with two
1485 // possibilities. Technically, only the first value is valid.
1486 // However, to fully determine that, all options of the remaining
1487 // disjunction will have to be evaluated algebraically, which is
1488 // not done.
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001489 xc1: *(xc2 & 8) | (xc4 & 9) | (xc5 & 9)
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001490 xc2: xc3 + 2
1491 xc3: 6 & xc1-2
1492 xc4: xc2 + 1
1493 xc5: xc2 + 2
1494
1495 // The above is resolved by setting xd1 explicitly.
1496 xd1: *(xd2 & 8) | xd4 & 9 | xd5 & 9
1497 xd2: xd3 + 2
1498 xd3: 6 & xd1-2
1499 xd4: xd2 + 1
1500 xd5: xd2 + 2
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001501
1502 // The above is resolved by setting xd1 explicitly to the wrong
1503 // value, resulting in an error.
1504 xe1: *(xe2 & 8) | xe4 & 9 | xe5 & 9
1505 xe2: xe3 + 2
1506 xe3: 6 & xe1-2
1507 xe4: xe2 + 1
1508 xe5: xe2 + 2
1509 xe1: 9
1510
1511 z1: *(z2 + 1) | z3 + 5
1512 z2: z3 + 2
1513 z3: z1 - 3
1514 z3: 8
1515 `,
1516 out: `<0>{` +
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001517 `xa1: 8, ` +
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001518 `xa2: 8, ` +
1519 `xa4: 10, ` +
1520 `xa3: 6, ` +
1521
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001522 `xb1: 8, ` +
1523 `xb2: 8, ` +
1524 `xb4: 10, ` +
1525 `xb3: 6, ` +
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001526
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001527 `xc1: (*8 | 9), ` + // not resolved because we use evalPartial
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001528 `xc2: 8, ` +
1529 `xc4: 9, ` +
1530 `xc5: 10, ` +
1531 `xc3: 6, ` +
1532
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001533 `xd1: (*8 | 9), ` + // TODO: eliminate 9?
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001534 `xd2: 8, ` +
1535 `xd4: 9, ` +
1536 `xd5: 10, ` +
1537 `xd3: 6, ` +
1538
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001539 `xe1: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
Marcel van Lohuizen50eea6b2019-02-19 18:30:15 +01001540 `xe2: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
1541 `xe4: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
1542 `xe5: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
1543 `xe3: _|_((6 & 7):cannot unify numbers 6 and 7), ` +
1544
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001545 `z1: (*11 | 13), ` + // 13 is eliminated with evalFull
1546 `z2: 10, ` +
1547 `z3: 8}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001548 }}
1549 rewriteHelper(t, testCases, evalPartial)
1550}
1551
1552func TestFullEval(t *testing.T) {
1553 testCases := []testCase{{
1554 desc: "detect conflicting value",
1555 in: `
1556 a: 8000.9
1557 a: 7080 | int`,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001558 out: `<0>{a: _|_((8000.9 & int):unsupported op &(float, (int)*))}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001559 }, {
1560 desc: "resolve all disjunctions",
1561 in: `
1562 service <Name>: {
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +01001563 name: string | *Name
1564 port: int | *7080
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001565 }
1566 service foo: _
1567 service bar: { port: 8000 }
1568 service baz: { name: "foobar" }
1569 `,
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +01001570 out: `<0>{service: <1>{<>: <2>(Name: string)-><3>{name: (string | *<2>.Name), port: (int | *7080)}, foo: <4>{name: "foo", port: 7080}, bar: <5>{name: "bar", port: 8000}, baz: <6>{name: "foobar", port: 7080}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001571 }, {
1572 desc: "field templates",
1573 in: `
1574 a: {
1575 <name>: int
1576 k: 1
1577 }
1578 b: {
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +01001579 <x>: { x: 0, y: *1 | int }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001580 v: {}
1581 w: { y: 0 }
1582 }
1583 b: { <y>: {} } // TODO: allow different name
1584 c: {
1585 <Name>: { name: Name, y: 1 }
1586 foo: {}
1587 bar: _
1588 }
1589 `,
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +01001590 out: `<0>{a: <1>{<>: <2>(name: string)->int, k: 1}, b: <3>{<>: <4>(x: string)->(<5>{x: 0, y: (*1 | int)} & <6>{}), v: <7>{x: 0, y: 1}, w: <8>{x: 0, y: 0}}, c: <9>{<>: <10>(Name: string)-><11>{name: <10>.Name, y: 1}, foo: <12>{name: "foo", y: 1}, bar: <13>{name: "bar", y: 1}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001591 }, {
1592 desc: "field comprehension",
1593 in: `
1594 a: { "\(k)": v for k, v in b if k < "d" if v > b.a }
1595 b: {
1596 a: 1
1597 b: 2
1598 c: 3
1599 d: 4
1600 }
1601 c: {
1602 "\(k)": v <-
1603 for k, v in b
1604 if k < "d"
1605 if v > b.a
1606 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001607 `,
1608 out: `<0>{a: <1>{b: 2, c: 3}, b: <2>{a: 1, b: 2, c: 3, d: 4}, c: <3>{b: 2, c: 3}}`,
1609 }, {
Marcel van Lohuizen66db9202018-12-17 19:02:08 +01001610 desc: "conditional field",
1611 in: `
1612 a: "foo" if b
1613 b: true
1614 c: {
1615 a: 3
1616 a: 3 if a > 1
1617 }
1618 `,
1619 out: `<0>{b: true, c: <1>{a: _|_(3:field a both generated by and referred to by field comprehension in same struct)}, a: "foo"}`,
1620 }, {
1621 desc: "referencing field in field comprehension",
1622 in: `
1623 a: { b c: 4 }
1624 a: {
1625 b d: 5
1626 "\(k)": v for k, v in b
1627 }
1628 `,
1629 out: `<0>{a: <1>{b: <2>{c: 4, d: 5}, c: 4, d: 5}}`,
1630 }, {
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +02001631 // TODO: rename EE and FF to E and F to check correct ordering.
1632
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001633 desc: "nested templates in one field",
1634 in: `
1635 a <A> b <B>: {
1636 name: A
1637 kind: B
1638 }
1639 a "A" b "B": _
1640 a "C" b "D": _
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +02001641 a "EE" b "FF": { c: "bar" }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001642 `,
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +02001643 out: `<0>{a: <1>{<>: <2>(A: string)-><3>{b: <4>{<>: <5>(B: string)-><6>{name: <2>.A, kind: <5>.B}, }}, ` +
1644 `A: <7>{b: <8>{<>: <9>(B: string)-><10>{name: <11>.A, kind: <9>.B}, ` +
1645 `B: <12>{name: "A", kind: "B"}}}, ` +
1646 `C: <13>{b: <14>{<>: <15>(B: string)-><16>{name: <17>.A, kind: <15>.B}, ` +
1647 `D: <18>{name: "C", kind: "D"}}}, ` +
1648 `EE: <19>{b: <20>{<>: <21>(B: string)-><22>{name: <23>.A, kind: <21>.B}, ` +
1649 `FF: <24>{name: "EE", kind: "FF", c: "bar"}}}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001650 }, {
1651 desc: "template unification within one struct",
1652 in: `
1653 a: {
1654 <A>: { name: A }
1655 <A>: { kind: A }
1656 }
1657 a "A": _
1658 a "C": _
1659 a "E": { c: "bar" }
1660 `,
1661 out: `<0>{a: <1>{<>: <2>(A: string)->(<3>{name: <2>.A} & <4>{kind: <2>.A}), ` +
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +02001662 `E: <5>{name: "E", kind: "E", c: "bar"}, ` +
1663 `A: <6>{name: "A", kind: "A"}, ` +
1664 `C: <7>{name: "C", kind: "C"}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001665 }, {
1666 desc: "field comprehensions with multiple keys",
1667 in: `
1668 a "\(x.a)" b "\(x.b)": x for x in [
1669 {a: "A", b: "B" },
1670 {a: "C", b: "D" },
1671 {a: "E", b: "F" },
1672 ]
1673
1674 "\(x.a)" "\(x.b)": x for x in [
1675 {a: "A", b: "B" },
1676 {a: "C", b: "D" },
1677 {a: "E", b: "F" },
1678 ]`,
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +02001679 out: `<0>{E: <1>{F: <2>{a: "E", b: "F"}}, ` +
1680 `a: <3>{` +
1681 `E: <4>{b: <5>{F: <6>{a: "E", b: "F"}}}, ` +
1682 `A: <7>{b: <8>{B: <9>{a: "A", b: "B"}}}, ` +
1683 `C: <10>{b: <11>{D: <12>{a: "C", b: "D"}}}}, ` +
1684 `A: <13>{B: <14>{a: "A", b: "B"}}, ` +
1685 `C: <15>{D: <16>{a: "C", b: "D"}}}`,
1686 // TODO: this order would be desirable.
1687 // out: `<0>{a: <1>{` +
1688 // `A: <2>{b: <3>{B: <4>{a: "A", b: "B"}}}, ` +
1689 // `C: <5>{b: <6>{D: <7>{a: "C", b: "D"}}}, ` +
1690 // `E: <8>{b: <9>{F: <10>{a: "E", b: "F"}}}}, ` +
1691 // `A: <11>{B: <12>{a: "A", b: "B"}}, ` +
1692 // `C: <13>{D: <14>{a: "C", b: "D"}}, ` +
1693 // `E: <15>{F: <16>{a: "E", b: "F"}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001694 }, {
1695 desc: "field comprehensions with templates",
1696 in: `
1697 num: 1
1698 a: {
1699 <A> <B>: {
1700 name: A
1701 kind: B
1702 } if num < 5
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001703 }
1704 a b c d: "bar"
1705 `,
1706 out: `<0>{num: 1, a: <1>{<>: <2>(A: string)-><3>{<>: <4>(B: string)-><5>{name: <2>.A, kind: <4>.B}, }, ` +
1707 `b: <6>{<>: <7>(B: string)-><8>{name: <9>.A, kind: <7>.B}, ` +
1708 `c: <10>{name: "b", kind: "c", ` +
1709 `d: "bar"}}}}`,
1710 }, {
1711 desc: "disjunctions of lists",
1712 in: `
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +01001713 l: *[ int, int ] | [ string, string ]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001714
1715 l1: [ "a", "b" ]
1716 l2: l & [ "c", "d" ]
1717 `,
1718 out: `<0>{l: [int,int], l1: ["a","b"], l2: ["c","d"]}`,
1719 }, {
Marcel van Lohuizene7e8f0d2019-02-06 12:29:58 +01001720 desc: "normalization",
1721 in: `
1722 a: string | string
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001723 b: *1 | *int
Marcel van Lohuizene7e8f0d2019-02-06 12:29:58 +01001724 c: *1.0 | *float
1725 `,
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001726 out: `<0>{a: string, b: int, c: float}`,
Marcel van Lohuizene7e8f0d2019-02-06 12:29:58 +01001727 }, {
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001728 desc: "default disambiguation and elimination",
Marcel van Lohuizene7e8f0d2019-02-06 12:29:58 +01001729 in: `
1730 a: *1 | int
1731 b: *3 | int
1732 c: a & b
1733 d: b & a
1734
1735 e: *1 | *1
1736 `,
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001737 out: `<0>{a: 1, b: 3, c: int, d: int, e: 1}`,
Marcel van Lohuizene7e8f0d2019-02-06 12:29:58 +01001738 }, {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001739 desc: "list comprehension",
1740 in: `
1741 // a: [ k for k: v in b if k < "d" if v > b.a ] // TODO test error using common iso colon
1742 a: [ k for k, v in b if k < "d" if v > b.a ]
1743 b: {
1744 a: 1
1745 b: 2
1746 c: 3
1747 d: 4
1748 }
1749 c: [ x for _, x in b for _, y in b if x < y ]
1750 d: [ x for x, _ in a ]
1751 `,
1752 out: `<0>{a: ["b","c"], b: <1>{a: 1, b: 2, c: 3, d: 4}, c: [1,1,1,2,2,3], d: [0,1]}`,
1753 }, {
1754 desc: "struct comprehension with template",
1755 in: `
1756 result: [ v for _, v in service ]
1757
1758 service <Name>: {
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +01001759 name: *Name | string
Marcel van Lohuizenf8132852019-04-26 12:16:18 +02001760 type: "service"
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +01001761 port: *7080 | int
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001762 }
1763 service foo: {}
1764 service bar: { port: 8000 }
1765 service baz: { name: "foobar" }
1766 `,
1767 out: `<0>{result: [` +
Marcel van Lohuizenf8132852019-04-26 12:16:18 +02001768 `<1>{name: "foo", type: "service", port: 7080},` +
1769 `<2>{name: "bar", type: "service", port: 8000},` +
1770 `<3>{name: "foobar", type: "service", port: 7080}], ` +
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001771
1772 `service: <4>{` +
Marcel van Lohuizenf8132852019-04-26 12:16:18 +02001773 `<>: <5>(Name: string)-><6>{name: (*<5>.Name | string), type: "service", port: (*7080 | int)}, ` +
1774 `foo: <7>{name: "foo", type: "service", port: 7080}, ` +
1775 `bar: <8>{name: "bar", type: "service", port: 8000}, ` +
1776 `baz: <9>{name: "foobar", type: "service", port: 7080}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001777 }, {
1778 desc: "resolutions in struct comprehension keys",
1779 in: `
Marcel van Lohuizen76b92b52018-12-16 10:47:03 +01001780 a: { "\(b + ".")": "a" for _, b in ["c"] }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001781 `,
1782 out: `<0>{a: <1>{c.: "a"}}`,
1783 }, {
1784 desc: "recursive evaluation within list",
1785 in: `
1786 l: [a]
1787 a: b & { c: "t" }
1788 b: {
1789 d: c
1790 c: string
1791 }
1792 l1: [a1]
1793 a1: b1 & { c: "t" }
1794 b1: {
1795 d: "s" + c
1796 c: string
1797 }
1798 `,
Jonathan Amsterdam0500c312019-02-16 18:04:09 -05001799 out: `<0>{` +
1800 `l: [<1>{c: "t", d: "t"}], ` +
1801 `a: <2>{c: "t", d: "t"}, ` +
1802 `b: <3>{c: string, d: string}, ` +
1803 `l1: [<4>{c: "t", d: "st"}], ` +
1804 `a1: <5>{c: "t", d: "st"}, ` +
1805 `b1: <6>{c: string, d: ("s" + <7>.c)}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001806 }, {
1807 desc: "ips",
1808 in: `
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001809 IP: 4*[ uint8 ]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001810
1811 Private:
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +01001812 *[ 192, 168, uint8, uint8 ] |
1813 [ 10, uint8, uint8, uint8] |
1814 [ 172, >=16 & <=32, uint8, uint8 ]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001815
1816 Inst: Private & [ _, 10, ... ]
1817
1818 MyIP: Inst & [_, _, 10, 10 ]
1819 `,
Jonathan Amsterdam0500c312019-02-16 18:04:09 -05001820 out: `<0>{` +
Marcel van Lohuizen4a360992019-05-11 18:18:31 +02001821 `IP: [(int & >=0 & int & <=255),(int & >=0 & int & <=255),(int & >=0 & int & <=255),(int & >=0 & int & <=255)], ` +
1822 `Private: [192,168,(int & >=0 & int & <=255),(int & >=0 & int & <=255)], ` +
1823 `Inst: [10,10,(int & >=0 & int & <=255),(int & >=0 & int & <=255)], ` +
Jonathan Amsterdam0500c312019-02-16 18:04:09 -05001824 `MyIP: [10,10,10,10]` +
1825 `}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001826 }, {
1827 desc: "complex interaction of groundness",
1828 in: `
1829 res: [ y & { d: "b" } for x in a for y in x ]
1830 res: [ a.b.c & { d: "b" } ]
1831
1832 a b <C>: { d: string, s: "a" + d }
1833 a b c d: string
1834 `,
1835 // TODO(perf): unification should catch shared node.
Jonathan Amsterdam0500c312019-02-16 18:04:09 -05001836 out: `<0>{res: [<1>{d: "b", s: "ab"}], ` +
1837 `a: <2>{b: <3>{<>: <4>(C: string)-><5>{d: string, s: ("a" + <5>.d)}, c: <6>{d: string, s: ("a" + <7>.d)}}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001838 }, {
1839 desc: "complex groundness 2",
1840 in: `
1841 r1: f1 & { y: "c" }
1842
1843 f1: { y: string, res: a.b.c & { d: y } }
1844
1845 a b c: { d: string, s: "a" + d }
1846 a b <C>: { d: string, s: "a" + d }
1847 a b c d: string
1848 `,
Jonathan Amsterdam0500c312019-02-16 18:04:09 -05001849 out: `<0>{r1: <1>{y: "c", res: <2>{d: "c", s: "ac"}}, f1: <3>{y: string, res: <4>{d: string, s: (("a" + <5>.d) & ("a" + <5>.d))}}, a: <6>{b: <7>{<>: <8>(C: string)-><9>{d: string, s: ("a" + <9>.d)}, c: <10>{d: string, s: (("a" + <11>.d) & ("a" + <11>.d))}}}}`,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001850 }, {
1851 desc: "references from template to concrete",
1852 in: `
1853 res: [t]
1854 t <X>: {
1855 a: c + b.str
1856 b str: string
1857 c: "X"
1858 }
1859 t x: { b str: "DDDD" }
1860 `,
1861 out: `<0>{res: [<1>{<>: <2>(X: string)-><3>{a: (<3>.c + <3>.b.str), c: "X", b: <4>{str: string}}, x: <5>{a: "XDDDD", c: "X", b: <6>{str: "DDDD"}}}], ` +
1862 `t: <7>{<>: <2>(X: string)-><3>{a: (<3>.c + <3>.b.str), c: "X", b: <4>{str: string}}, x: <8>{a: "XDDDD", c: "X", b: <9>{str: "DDDD"}}}}`,
Marcel van Lohuizen7f48df72019-02-01 17:24:59 +01001863 }, {
1864 // TODO: A nice property for CUE to have would be that evaluation time
1865 // is proportional to the number of output nodes (note that this is
1866 // not the same as saying that the running time is O(n)).
1867 // We should probably disallow shenanigans like the one below. But until
1868 // this is allowed, it should at least be correct. At least we are not
1869 // making reentrant coding easy.
1870 desc: "reentrance",
1871 in: `
1872 // This indirection is needed to avoid binding references to fib
1873 // within fib to the instantiated version.
1874 fibRec: {nn: int, out: (fib & {n: nn}).out}
1875 fib: {
1876 n: int
1877
1878 out: (fibRec & {nn: n - 2}).out + (fibRec & {nn: n - 1}).out if n >= 2
1879 out: n if n < 2
1880 }
1881 fib2: (fib & {n: 2}).out
1882 fib7: (fib & {n: 7}).out
1883 fib12: (fib & {n: 12}).out
1884 `,
1885 out: `<0>{fibRec: <1>{nn: int, out: _|_((<2>.fib & <3>{n: <4>.nn}).out:undefined field "out")}, fib: <5>{n: int}, ` +
1886 `fib2: 1, ` +
1887 `fib7: 13, ` +
1888 `fib12: 144}`,
Marcel van Lohuizen2601ab82019-04-03 23:04:16 +02001889 }, {
1890 desc: "Issue #23",
1891 in: `
1892 x: {a:1}|{a:2}
1893 y: x & {a:3}
1894 `,
1895 out: `<3>{x: _|_((<0>{a: 1} | <1>{a: 2}):more than one element remaining (<0>{a: 1} and <1>{a: 2})), y: _|_((<4>.x & <5>{a: 3}):empty disjunction: <2>{a: (1 & 3)})}`,
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +02001896 }, {
1897 desc: "cannot resolve references that would be ambiguous",
1898 in: `
1899 a1: *0 | 1
1900 a1: a3 - a2
1901 a2: *0 | 1
1902 a2: a3 - a1
1903 a3: 1
1904
1905 b1: (*0 | 1) & b2
1906 b2: (0 | *1) & b1
1907
1908 c1: (*{a:1} | {b:1}) & c2
1909 c2: (*{a:2} | {b:2}) & c1
1910 `,
1911 out: `<4>{` +
1912 `a1: _|_(((*0 | 1) & (<5>.a3 - <5>.a2)):cycle detected), ` +
1913 `a3: 1, ` +
1914 `a2: _|_(((*0 | 1) & (<5>.a3 - <5>.a1)):cycle detected), ` +
1915 `b1: _|_((0 | 1):more than one element remaining (0 and 1)), ` +
1916 `b2: _|_((0 | 1):more than one element remaining (0 and 1)), ` +
1917 `c1: _|_((<0>{a: 1, b: 2} | <1>{a: 2, b: 1}):more than one element remaining (<0>{a: 1, b: 2} and <1>{a: 2, b: 1})), ` +
1918 `c2: _|_((<2>{a: 2, b: 1} | <3>{a: 1, b: 2}):more than one element remaining (<2>{a: 2, b: 1} and <3>{a: 1, b: 2}))}`,
Marcel van Lohuizen7f48df72019-02-01 17:24:59 +01001919 }}
1920 rewriteHelper(t, testCases, evalFull)
1921}
1922
1923func TestX(t *testing.T) {
1924 t.Skip()
1925
1926 // Don't remove. For debugging.
1927 testCases := []testCase{{
1928 in: `
1929 `,
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001930 }}
1931 rewriteHelper(t, testCases, evalFull)
1932}