...
1// Issues: #667, #695, #622
2
3// Comparing against bottom is not officially supported by the spec.
4// In practice it is used for a variety of purposes.
5//
6// TODO: It should really be replaced with two builtins:
7//
8// - exists(reference): check if a certain field exists.
9// - isvalid(value): check if a certain value is valid (recursively).
10//
11// For now it implements something in between these two: it fails if a value
12// resolves to an error, but not necessarily if it does so recursively.
13// Although adding a recursive check is easy, it will break existing
14// configurations, as a recursive evaluation will trigger cycles where these
15// are perhaps not expected.
16
17// To verify these tests, each result should have a field
18//
19// X: "user@example.com"
20//
21// for the large and medium examples and
22//
23// X: "message: hello"
24//
25// for the simple example.
26//
27// These are not automatically tested using CUE to avoid interfering with the
28// evaluation.
29
30-- in.cue --
31import "regexp"
32
33simple: {
34 #message: #"^(message: (?P<message>.*))?$"#
35
36 p1: {
37 X: "message: hello"
38 #aux: {
39 if Y.message == _|_ {
40 message: ""
41 }
42 if Y.message != _|_ {
43 message: "message: " + Y.message
44 }
45 }
46
47 Y: regexp.FindNamedSubmatch(#message, X)
48 X: #aux.message
49 }
50
51 p2: {
52 #aux: {
53 if Y.message == _|_ {
54 message: ""
55 }
56 if Y.message != _|_ {
57 message: "message: " + Y.message
58 }
59 }
60
61 X: "message: hello"
62 Y: regexp.FindNamedSubmatch(#message, X)
63 X: #aux.message
64 }
65
66 p3: {
67 #aux: {
68 if Y.message == _|_ {
69 message: ""
70 }
71 if Y.message != _|_ {
72 message: "message: " + Y.message
73 }
74 }
75
76 Y: regexp.FindNamedSubmatch(#message, X)
77 X: "message: hello"
78 X: #aux.message
79 }
80
81 p4: {
82 X: #aux.message
83 #aux: {
84 if Y.message == _|_ {
85 message: ""
86 }
87 if Y.message != _|_ {
88 message: "message: " + Y.message
89 }
90 }
91
92 Y: regexp.FindNamedSubmatch(#message, X)
93 X: "message: hello"
94 }
95
96 p5: {
97 #aux: {
98 if Y.message == _|_ {
99 message: ""
100 }
101 if Y.message != _|_ {
102 message: "message: " + Y.message
103 }
104 }
105
106 X: #aux.message
107 Y: regexp.FindNamedSubmatch(#message, X)
108 X: "message: hello"
109 }
110
111 p6: {
112 #aux: {
113 if Y.message == _|_ {
114 message: ""
115 }
116 if Y.message != _|_ {
117 message: "message: " + Y.message
118 }
119 }
120
121 Y: regexp.FindNamedSubmatch(#message, X)
122 X: #aux.message
123 X: "message: hello"
124 }
125}
126
127medium: {
128 #userHostPort: #"^((?P<userinfo>[[:alnum:]]*)@)?(?P<host>[[:alnum:].]+)$"#
129
130 p1: {
131 Y: {
132 userinfo: "user"
133 host: "mod.test"
134 }
135
136 // X: "user@example.com"
137 X: #X.userinfo + #X.host
138
139 #X: {
140 // userinfo: "user@"
141 // host: "mod.test"
142
143 if Y.userinfo == _|_ {
144 userinfo: ""
145 }
146 if Y.userinfo != _|_ {
147 userinfo: Y.userinfo + "@"
148 }
149
150 host: Y.host
151 }
152
153 Y: {
154 // userinfo: "user"
155 // host: "mod.test"
156
157 if #Y.userinfo != _|_ {
158 userinfo: #Y.userinfo
159 }
160
161 host: #Y.host
162 }
163
164 #Y: regexp.FindNamedSubmatch(#userHostPort, X)
165 }
166
167 p2: {
168 X: #X.userinfo + #X.host
169
170 Y: {
171 userinfo: "user"
172 host: "mod.test"
173 }
174
175 #X: {
176 if Y.userinfo == _|_ {
177 userinfo: ""
178 }
179 if Y.userinfo != _|_ {
180 userinfo: Y.userinfo + "@"
181 }
182
183 host: Y.host
184 }
185
186 Y: {
187 if #Y.userinfo != _|_ {
188 userinfo: #Y.userinfo
189 }
190
191 host: #Y.host
192 }
193
194 #Y: regexp.FindNamedSubmatch(#userHostPort, X)
195 }
196
197 p3: {
198 X: #X.userinfo + #X.host
199
200 #X: {
201 if Y.userinfo == _|_ {
202 userinfo: ""
203 }
204 if Y.userinfo != _|_ {
205 userinfo: Y.userinfo + "@"
206 }
207
208 host: Y.host
209 }
210
211 Y: {
212 userinfo: "user"
213 host: "mod.test"
214 }
215
216 Y: {
217 if #Y.userinfo != _|_ {
218 userinfo: #Y.userinfo
219 }
220
221 host: #Y.host
222 }
223
224 #Y: regexp.FindNamedSubmatch(#userHostPort, X)
225 }
226
227 p4: {
228 X: #X.userinfo + #X.host
229
230 #X: {
231 if Y.userinfo == _|_ {
232 userinfo: ""
233 }
234 if Y.userinfo != _|_ {
235 userinfo: Y.userinfo + "@"
236 }
237
238 host: Y.host
239 }
240
241 Y: {
242 if #Y.userinfo != _|_ {
243 userinfo: #Y.userinfo
244 }
245
246 host: #Y.host
247 }
248
249 #Y: regexp.FindNamedSubmatch(#userHostPort, X)
250
251 Y: {
252 userinfo: "user"
253 host: "mod.test"
254 }
255 }
256}
257-- out/eval/stats --
258Leaks: 0
259Freed: 85
260Reused: 73
261Allocs: 12
262Retain: 200
263
264Unifications: 85
265Conjuncts: 126
266Disjuncts: 194
267-- out/evalalpha --
268(struct){
269 simple: (struct){
270 #message: (string){ "^(message: (?P<message>.*))?$" }
271 p1: (struct){
272 X: (string){ "message: hello" }
273 #aux: (#struct){
274 message: (string){ "message: hello" }
275 }
276 Y: (struct){
277 message: (string){ "hello" }
278 }
279 }
280 p2: (struct){
281 #aux: (#struct){
282 message: (string){ "message: hello" }
283 }
284 X: (string){ "message: hello" }
285 Y: (struct){
286 message: (string){ "hello" }
287 }
288 }
289 p3: (struct){
290 #aux: (#struct){
291 message: (string){ "message: hello" }
292 }
293 Y: (struct){
294 message: (string){ "hello" }
295 }
296 X: (string){ "message: hello" }
297 }
298 p4: (struct){
299 X: (string){ "message: hello" }
300 #aux: (#struct){
301 message: (string){ "message: hello" }
302 }
303 Y: (struct){
304 message: (string){ "hello" }
305 }
306 }
307 p5: (struct){
308 #aux: (#struct){
309 message: (string){ "message: hello" }
310 }
311 X: (string){ "message: hello" }
312 Y: (struct){
313 message: (string){ "hello" }
314 }
315 }
316 p6: (struct){
317 #aux: (#struct){
318 message: (string){ "message: hello" }
319 }
320 Y: (struct){
321 message: (string){ "hello" }
322 }
323 X: (string){ "message: hello" }
324 }
325 }
326 medium: (struct){
327 #userHostPort: (string){ "^((?P<userinfo>[[:alnum:]]*)@)?(?P<host>[[:alnum:].]+)$" }
328 p1: (struct){
329 Y: (struct){
330 userinfo: (string){ "user" }
331 host: (string){ "mod.test" }
332 }
333 X: (string){ "user@mod.test" }
334 #X: (#struct){
335 userinfo: (string){ "user@" }
336 host: (string){ "mod.test" }
337 }
338 #Y: (#struct){
339 host: (string){ "mod.test" }
340 userinfo: (string){ "user" }
341 }
342 }
343 p2: (struct){
344 X: (string){ "user@mod.test" }
345 Y: (struct){
346 userinfo: (string){ "user" }
347 host: (string){ "mod.test" }
348 }
349 #X: (#struct){
350 userinfo: (string){ "user@" }
351 host: (string){ "mod.test" }
352 }
353 #Y: (#struct){
354 userinfo: (string){ "user" }
355 host: (string){ "mod.test" }
356 }
357 }
358 p3: (struct){
359 X: (string){ "user@mod.test" }
360 #X: (#struct){
361 userinfo: (string){ "user@" }
362 host: (string){ "mod.test" }
363 }
364 Y: (struct){
365 userinfo: (string){ "user" }
366 host: (string){ "mod.test" }
367 }
368 #Y: (#struct){
369 userinfo: (string){ "user" }
370 host: (string){ "mod.test" }
371 }
372 }
373 p4: (struct){
374 X: (string){ "user@mod.test" }
375 #X: (#struct){
376 userinfo: (string){ "user@" }
377 host: (string){ "mod.test" }
378 }
379 Y: (struct){
380 userinfo: (string){ "user" }
381 host: (string){ "mod.test" }
382 }
383 #Y: (#struct){
384 userinfo: (string){ "user" }
385 host: (string){ "mod.test" }
386 }
387 }
388 }
389}
390-- diff/-out/evalalpha<==>+out/eval --
391diff old new
392--- old
393+++ new
394@@ -84,38 +84,38 @@
395 host: (string){ "mod.test" }
396 }
397 #Y: (#struct){
398- host: (string){ "mod.test" }
399- userinfo: (string){ "user" }
400- }
401- }
402- p3: (struct){
403- X: (string){ "user@mod.test" }
404- #X: (#struct){
405- userinfo: (string){ "user@" }
406- host: (string){ "mod.test" }
407- }
408- Y: (struct){
409- userinfo: (string){ "user" }
410- host: (string){ "mod.test" }
411- }
412- #Y: (#struct){
413- host: (string){ "mod.test" }
414- userinfo: (string){ "user" }
415- }
416- }
417- p4: (struct){
418- X: (string){ "user@mod.test" }
419- #X: (#struct){
420- userinfo: (string){ "user@" }
421- host: (string){ "mod.test" }
422- }
423- Y: (struct){
424- userinfo: (string){ "user" }
425- host: (string){ "mod.test" }
426- }
427- #Y: (#struct){
428- host: (string){ "mod.test" }
429- userinfo: (string){ "user" }
430+ userinfo: (string){ "user" }
431+ host: (string){ "mod.test" }
432+ }
433+ }
434+ p3: (struct){
435+ X: (string){ "user@mod.test" }
436+ #X: (#struct){
437+ userinfo: (string){ "user@" }
438+ host: (string){ "mod.test" }
439+ }
440+ Y: (struct){
441+ userinfo: (string){ "user" }
442+ host: (string){ "mod.test" }
443+ }
444+ #Y: (#struct){
445+ userinfo: (string){ "user" }
446+ host: (string){ "mod.test" }
447+ }
448+ }
449+ p4: (struct){
450+ X: (string){ "user@mod.test" }
451+ #X: (#struct){
452+ userinfo: (string){ "user@" }
453+ host: (string){ "mod.test" }
454+ }
455+ Y: (struct){
456+ userinfo: (string){ "user" }
457+ host: (string){ "mod.test" }
458+ }
459+ #Y: (#struct){
460+ userinfo: (string){ "user" }
461+ host: (string){ "mod.test" }
462 }
463 }
464 }
465-- diff/todo/p3 --
466Reordering
467-- out/eval --
468(struct){
469 simple: (struct){
470 #message: (string){ "^(message: (?P<message>.*))?$" }
471 p1: (struct){
472 X: (string){ "message: hello" }
473 #aux: (#struct){
474 message: (string){ "message: hello" }
475 }
476 Y: (struct){
477 message: (string){ "hello" }
478 }
479 }
480 p2: (struct){
481 #aux: (#struct){
482 message: (string){ "message: hello" }
483 }
484 X: (string){ "message: hello" }
485 Y: (struct){
486 message: (string){ "hello" }
487 }
488 }
489 p3: (struct){
490 #aux: (#struct){
491 message: (string){ "message: hello" }
492 }
493 Y: (struct){
494 message: (string){ "hello" }
495 }
496 X: (string){ "message: hello" }
497 }
498 p4: (struct){
499 X: (string){ "message: hello" }
500 #aux: (#struct){
501 message: (string){ "message: hello" }
502 }
503 Y: (struct){
504 message: (string){ "hello" }
505 }
506 }
507 p5: (struct){
508 #aux: (#struct){
509 message: (string){ "message: hello" }
510 }
511 X: (string){ "message: hello" }
512 Y: (struct){
513 message: (string){ "hello" }
514 }
515 }
516 p6: (struct){
517 #aux: (#struct){
518 message: (string){ "message: hello" }
519 }
520 Y: (struct){
521 message: (string){ "hello" }
522 }
523 X: (string){ "message: hello" }
524 }
525 }
526 medium: (struct){
527 #userHostPort: (string){ "^((?P<userinfo>[[:alnum:]]*)@)?(?P<host>[[:alnum:].]+)$" }
528 p1: (struct){
529 Y: (struct){
530 userinfo: (string){ "user" }
531 host: (string){ "mod.test" }
532 }
533 X: (string){ "user@mod.test" }
534 #X: (#struct){
535 userinfo: (string){ "user@" }
536 host: (string){ "mod.test" }
537 }
538 #Y: (#struct){
539 host: (string){ "mod.test" }
540 userinfo: (string){ "user" }
541 }
542 }
543 p2: (struct){
544 X: (string){ "user@mod.test" }
545 Y: (struct){
546 userinfo: (string){ "user" }
547 host: (string){ "mod.test" }
548 }
549 #X: (#struct){
550 userinfo: (string){ "user@" }
551 host: (string){ "mod.test" }
552 }
553 #Y: (#struct){
554 host: (string){ "mod.test" }
555 userinfo: (string){ "user" }
556 }
557 }
558 p3: (struct){
559 X: (string){ "user@mod.test" }
560 #X: (#struct){
561 userinfo: (string){ "user@" }
562 host: (string){ "mod.test" }
563 }
564 Y: (struct){
565 userinfo: (string){ "user" }
566 host: (string){ "mod.test" }
567 }
568 #Y: (#struct){
569 host: (string){ "mod.test" }
570 userinfo: (string){ "user" }
571 }
572 }
573 p4: (struct){
574 X: (string){ "user@mod.test" }
575 #X: (#struct){
576 userinfo: (string){ "user@" }
577 host: (string){ "mod.test" }
578 }
579 Y: (struct){
580 userinfo: (string){ "user" }
581 host: (string){ "mod.test" }
582 }
583 #Y: (#struct){
584 host: (string){ "mod.test" }
585 userinfo: (string){ "user" }
586 }
587 }
588 }
589}
590-- out/compile --
591--- in.cue
592{
593 simple: {
594 #message: "^(message: (?P<message>.*))?$"
595 p1: {
596 X: "message: hello"
597 #aux: {
598 if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) {
599 message: ""
600 }
601 if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) {
602 message: ("message: " + 〈2;Y〉.message)
603 }
604 }
605 Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉)
606 X: 〈0;#aux〉.message
607 }
608 p2: {
609 #aux: {
610 if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) {
611 message: ""
612 }
613 if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) {
614 message: ("message: " + 〈2;Y〉.message)
615 }
616 }
617 X: "message: hello"
618 Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉)
619 X: 〈0;#aux〉.message
620 }
621 p3: {
622 #aux: {
623 if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) {
624 message: ""
625 }
626 if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) {
627 message: ("message: " + 〈2;Y〉.message)
628 }
629 }
630 Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉)
631 X: "message: hello"
632 X: 〈0;#aux〉.message
633 }
634 p4: {
635 X: 〈0;#aux〉.message
636 #aux: {
637 if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) {
638 message: ""
639 }
640 if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) {
641 message: ("message: " + 〈2;Y〉.message)
642 }
643 }
644 Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉)
645 X: "message: hello"
646 }
647 p5: {
648 #aux: {
649 if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) {
650 message: ""
651 }
652 if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) {
653 message: ("message: " + 〈2;Y〉.message)
654 }
655 }
656 X: 〈0;#aux〉.message
657 Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉)
658 X: "message: hello"
659 }
660 p6: {
661 #aux: {
662 if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) {
663 message: ""
664 }
665 if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) {
666 message: ("message: " + 〈2;Y〉.message)
667 }
668 }
669 Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉)
670 X: 〈0;#aux〉.message
671 X: "message: hello"
672 }
673 }
674 medium: {
675 #userHostPort: "^((?P<userinfo>[[:alnum:]]*)@)?(?P<host>[[:alnum:].]+)$"
676 p1: {
677 Y: {
678 userinfo: "user"
679 host: "mod.test"
680 }
681 X: (〈0;#X〉.userinfo + 〈0;#X〉.host)
682 #X: {
683 if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) {
684 userinfo: ""
685 }
686 if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
687 userinfo: (〈2;Y〉.userinfo + "@")
688 }
689 host: 〈1;Y〉.host
690 }
691 Y: {
692 if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
693 userinfo: 〈2;#Y〉.userinfo
694 }
695 host: 〈1;#Y〉.host
696 }
697 #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉)
698 }
699 p2: {
700 X: (〈0;#X〉.userinfo + 〈0;#X〉.host)
701 Y: {
702 userinfo: "user"
703 host: "mod.test"
704 }
705 #X: {
706 if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) {
707 userinfo: ""
708 }
709 if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
710 userinfo: (〈2;Y〉.userinfo + "@")
711 }
712 host: 〈1;Y〉.host
713 }
714 Y: {
715 if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
716 userinfo: 〈2;#Y〉.userinfo
717 }
718 host: 〈1;#Y〉.host
719 }
720 #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉)
721 }
722 p3: {
723 X: (〈0;#X〉.userinfo + 〈0;#X〉.host)
724 #X: {
725 if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) {
726 userinfo: ""
727 }
728 if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
729 userinfo: (〈2;Y〉.userinfo + "@")
730 }
731 host: 〈1;Y〉.host
732 }
733 Y: {
734 userinfo: "user"
735 host: "mod.test"
736 }
737 Y: {
738 if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
739 userinfo: 〈2;#Y〉.userinfo
740 }
741 host: 〈1;#Y〉.host
742 }
743 #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉)
744 }
745 p4: {
746 X: (〈0;#X〉.userinfo + 〈0;#X〉.host)
747 #X: {
748 if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) {
749 userinfo: ""
750 }
751 if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
752 userinfo: (〈2;Y〉.userinfo + "@")
753 }
754 host: 〈1;Y〉.host
755 }
756 Y: {
757 if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) {
758 userinfo: 〈2;#Y〉.userinfo
759 }
760 host: 〈1;#Y〉.host
761 }
762 #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉)
763 Y: {
764 userinfo: "user"
765 host: "mod.test"
766 }
767 }
768 }
769}
View as plain text