// Issues: #667, #695, #622 // Comparing against bottom is not officially supported by the spec. // In practice it is used for a variety of purposes. // // TODO: It should really be replaced with two builtins: // // - exists(reference): check if a certain field exists. // - isvalid(value): check if a certain value is valid (recursively). // // For now it implements something in between these two: it fails if a value // resolves to an error, but not necessarily if it does so recursively. // Although adding a recursive check is easy, it will break existing // configurations, as a recursive evaluation will trigger cycles where these // are perhaps not expected. // To verify these tests, each result should have a field // // X: "user@example.com" // // for the large and medium examples and // // X: "message: hello" // // for the simple example. // // These are not automatically tested using CUE to avoid interfering with the // evaluation. -- in.cue -- import "regexp" simple: { #message: #"^(message: (?P.*))?$"# p1: { X: "message: hello" #aux: { if Y.message == _|_ { message: "" } if Y.message != _|_ { message: "message: " + Y.message } } Y: regexp.FindNamedSubmatch(#message, X) X: #aux.message } p2: { #aux: { if Y.message == _|_ { message: "" } if Y.message != _|_ { message: "message: " + Y.message } } X: "message: hello" Y: regexp.FindNamedSubmatch(#message, X) X: #aux.message } p3: { #aux: { if Y.message == _|_ { message: "" } if Y.message != _|_ { message: "message: " + Y.message } } Y: regexp.FindNamedSubmatch(#message, X) X: "message: hello" X: #aux.message } p4: { X: #aux.message #aux: { if Y.message == _|_ { message: "" } if Y.message != _|_ { message: "message: " + Y.message } } Y: regexp.FindNamedSubmatch(#message, X) X: "message: hello" } p5: { #aux: { if Y.message == _|_ { message: "" } if Y.message != _|_ { message: "message: " + Y.message } } X: #aux.message Y: regexp.FindNamedSubmatch(#message, X) X: "message: hello" } p6: { #aux: { if Y.message == _|_ { message: "" } if Y.message != _|_ { message: "message: " + Y.message } } Y: regexp.FindNamedSubmatch(#message, X) X: #aux.message X: "message: hello" } } medium: { #userHostPort: #"^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)$"# p1: { Y: { userinfo: "user" host: "mod.test" } // X: "user@example.com" X: #X.userinfo + #X.host #X: { // userinfo: "user@" // host: "mod.test" if Y.userinfo == _|_ { userinfo: "" } if Y.userinfo != _|_ { userinfo: Y.userinfo + "@" } host: Y.host } Y: { // userinfo: "user" // host: "mod.test" if #Y.userinfo != _|_ { userinfo: #Y.userinfo } host: #Y.host } #Y: regexp.FindNamedSubmatch(#userHostPort, X) } p2: { X: #X.userinfo + #X.host Y: { userinfo: "user" host: "mod.test" } #X: { if Y.userinfo == _|_ { userinfo: "" } if Y.userinfo != _|_ { userinfo: Y.userinfo + "@" } host: Y.host } Y: { if #Y.userinfo != _|_ { userinfo: #Y.userinfo } host: #Y.host } #Y: regexp.FindNamedSubmatch(#userHostPort, X) } p3: { X: #X.userinfo + #X.host #X: { if Y.userinfo == _|_ { userinfo: "" } if Y.userinfo != _|_ { userinfo: Y.userinfo + "@" } host: Y.host } Y: { userinfo: "user" host: "mod.test" } Y: { if #Y.userinfo != _|_ { userinfo: #Y.userinfo } host: #Y.host } #Y: regexp.FindNamedSubmatch(#userHostPort, X) } p4: { X: #X.userinfo + #X.host #X: { if Y.userinfo == _|_ { userinfo: "" } if Y.userinfo != _|_ { userinfo: Y.userinfo + "@" } host: Y.host } Y: { if #Y.userinfo != _|_ { userinfo: #Y.userinfo } host: #Y.host } #Y: regexp.FindNamedSubmatch(#userHostPort, X) Y: { userinfo: "user" host: "mod.test" } } } -- out/eval/stats -- Leaks: 0 Freed: 85 Reused: 73 Allocs: 12 Retain: 200 Unifications: 85 Conjuncts: 126 Disjuncts: 194 -- out/evalalpha -- (struct){ simple: (struct){ #message: (string){ "^(message: (?P.*))?$" } p1: (struct){ X: (string){ "message: hello" } #aux: (#struct){ message: (string){ "message: hello" } } Y: (struct){ message: (string){ "hello" } } } p2: (struct){ #aux: (#struct){ message: (string){ "message: hello" } } X: (string){ "message: hello" } Y: (struct){ message: (string){ "hello" } } } p3: (struct){ #aux: (#struct){ message: (string){ "message: hello" } } Y: (struct){ message: (string){ "hello" } } X: (string){ "message: hello" } } p4: (struct){ X: (string){ "message: hello" } #aux: (#struct){ message: (string){ "message: hello" } } Y: (struct){ message: (string){ "hello" } } } p5: (struct){ #aux: (#struct){ message: (string){ "message: hello" } } X: (string){ "message: hello" } Y: (struct){ message: (string){ "hello" } } } p6: (struct){ #aux: (#struct){ message: (string){ "message: hello" } } Y: (struct){ message: (string){ "hello" } } X: (string){ "message: hello" } } } medium: (struct){ #userHostPort: (string){ "^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)$" } p1: (struct){ Y: (struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } X: (string){ "user@mod.test" } #X: (#struct){ userinfo: (string){ "user@" } host: (string){ "mod.test" } } #Y: (#struct){ host: (string){ "mod.test" } userinfo: (string){ "user" } } } p2: (struct){ X: (string){ "user@mod.test" } Y: (struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } #X: (#struct){ userinfo: (string){ "user@" } host: (string){ "mod.test" } } #Y: (#struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } } p3: (struct){ X: (string){ "user@mod.test" } #X: (#struct){ userinfo: (string){ "user@" } host: (string){ "mod.test" } } Y: (struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } #Y: (#struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } } p4: (struct){ X: (string){ "user@mod.test" } #X: (#struct){ userinfo: (string){ "user@" } host: (string){ "mod.test" } } Y: (struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } #Y: (#struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } } } } -- diff/-out/evalalpha<==>+out/eval -- diff old new --- old +++ new @@ -84,38 +84,38 @@ host: (string){ "mod.test" } } #Y: (#struct){ - host: (string){ "mod.test" } - userinfo: (string){ "user" } - } - } - p3: (struct){ - X: (string){ "user@mod.test" } - #X: (#struct){ - userinfo: (string){ "user@" } - host: (string){ "mod.test" } - } - Y: (struct){ - userinfo: (string){ "user" } - host: (string){ "mod.test" } - } - #Y: (#struct){ - host: (string){ "mod.test" } - userinfo: (string){ "user" } - } - } - p4: (struct){ - X: (string){ "user@mod.test" } - #X: (#struct){ - userinfo: (string){ "user@" } - host: (string){ "mod.test" } - } - Y: (struct){ - userinfo: (string){ "user" } - host: (string){ "mod.test" } - } - #Y: (#struct){ - host: (string){ "mod.test" } - userinfo: (string){ "user" } + userinfo: (string){ "user" } + host: (string){ "mod.test" } + } + } + p3: (struct){ + X: (string){ "user@mod.test" } + #X: (#struct){ + userinfo: (string){ "user@" } + host: (string){ "mod.test" } + } + Y: (struct){ + userinfo: (string){ "user" } + host: (string){ "mod.test" } + } + #Y: (#struct){ + userinfo: (string){ "user" } + host: (string){ "mod.test" } + } + } + p4: (struct){ + X: (string){ "user@mod.test" } + #X: (#struct){ + userinfo: (string){ "user@" } + host: (string){ "mod.test" } + } + Y: (struct){ + userinfo: (string){ "user" } + host: (string){ "mod.test" } + } + #Y: (#struct){ + userinfo: (string){ "user" } + host: (string){ "mod.test" } } } } -- diff/todo/p3 -- Reordering -- out/eval -- (struct){ simple: (struct){ #message: (string){ "^(message: (?P.*))?$" } p1: (struct){ X: (string){ "message: hello" } #aux: (#struct){ message: (string){ "message: hello" } } Y: (struct){ message: (string){ "hello" } } } p2: (struct){ #aux: (#struct){ message: (string){ "message: hello" } } X: (string){ "message: hello" } Y: (struct){ message: (string){ "hello" } } } p3: (struct){ #aux: (#struct){ message: (string){ "message: hello" } } Y: (struct){ message: (string){ "hello" } } X: (string){ "message: hello" } } p4: (struct){ X: (string){ "message: hello" } #aux: (#struct){ message: (string){ "message: hello" } } Y: (struct){ message: (string){ "hello" } } } p5: (struct){ #aux: (#struct){ message: (string){ "message: hello" } } X: (string){ "message: hello" } Y: (struct){ message: (string){ "hello" } } } p6: (struct){ #aux: (#struct){ message: (string){ "message: hello" } } Y: (struct){ message: (string){ "hello" } } X: (string){ "message: hello" } } } medium: (struct){ #userHostPort: (string){ "^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)$" } p1: (struct){ Y: (struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } X: (string){ "user@mod.test" } #X: (#struct){ userinfo: (string){ "user@" } host: (string){ "mod.test" } } #Y: (#struct){ host: (string){ "mod.test" } userinfo: (string){ "user" } } } p2: (struct){ X: (string){ "user@mod.test" } Y: (struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } #X: (#struct){ userinfo: (string){ "user@" } host: (string){ "mod.test" } } #Y: (#struct){ host: (string){ "mod.test" } userinfo: (string){ "user" } } } p3: (struct){ X: (string){ "user@mod.test" } #X: (#struct){ userinfo: (string){ "user@" } host: (string){ "mod.test" } } Y: (struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } #Y: (#struct){ host: (string){ "mod.test" } userinfo: (string){ "user" } } } p4: (struct){ X: (string){ "user@mod.test" } #X: (#struct){ userinfo: (string){ "user@" } host: (string){ "mod.test" } } Y: (struct){ userinfo: (string){ "user" } host: (string){ "mod.test" } } #Y: (#struct){ host: (string){ "mod.test" } userinfo: (string){ "user" } } } } } -- out/compile -- --- in.cue { simple: { #message: "^(message: (?P.*))?$" p1: { X: "message: hello" #aux: { if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) { message: "" } if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) { message: ("message: " + 〈2;Y〉.message) } } Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉) X: 〈0;#aux〉.message } p2: { #aux: { if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) { message: "" } if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) { message: ("message: " + 〈2;Y〉.message) } } X: "message: hello" Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉) X: 〈0;#aux〉.message } p3: { #aux: { if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) { message: "" } if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) { message: ("message: " + 〈2;Y〉.message) } } Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉) X: "message: hello" X: 〈0;#aux〉.message } p4: { X: 〈0;#aux〉.message #aux: { if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) { message: "" } if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) { message: ("message: " + 〈2;Y〉.message) } } Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉) X: "message: hello" } p5: { #aux: { if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) { message: "" } if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) { message: ("message: " + 〈2;Y〉.message) } } X: 〈0;#aux〉.message Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉) X: "message: hello" } p6: { #aux: { if (〈1;Y〉.message == _|_(explicit error (_|_ literal) in source)) { message: "" } if (〈1;Y〉.message != _|_(explicit error (_|_ literal) in source)) { message: ("message: " + 〈2;Y〉.message) } } Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#message〉, 〈0;X〉) X: 〈0;#aux〉.message X: "message: hello" } } medium: { #userHostPort: "^((?P[[:alnum:]]*)@)?(?P[[:alnum:].]+)$" p1: { Y: { userinfo: "user" host: "mod.test" } X: (〈0;#X〉.userinfo + 〈0;#X〉.host) #X: { if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) { userinfo: "" } if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { userinfo: (〈2;Y〉.userinfo + "@") } host: 〈1;Y〉.host } Y: { if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { userinfo: 〈2;#Y〉.userinfo } host: 〈1;#Y〉.host } #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉) } p2: { X: (〈0;#X〉.userinfo + 〈0;#X〉.host) Y: { userinfo: "user" host: "mod.test" } #X: { if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) { userinfo: "" } if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { userinfo: (〈2;Y〉.userinfo + "@") } host: 〈1;Y〉.host } Y: { if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { userinfo: 〈2;#Y〉.userinfo } host: 〈1;#Y〉.host } #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉) } p3: { X: (〈0;#X〉.userinfo + 〈0;#X〉.host) #X: { if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) { userinfo: "" } if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { userinfo: (〈2;Y〉.userinfo + "@") } host: 〈1;Y〉.host } Y: { userinfo: "user" host: "mod.test" } Y: { if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { userinfo: 〈2;#Y〉.userinfo } host: 〈1;#Y〉.host } #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉) } p4: { X: (〈0;#X〉.userinfo + 〈0;#X〉.host) #X: { if (〈1;Y〉.userinfo == _|_(explicit error (_|_ literal) in source)) { userinfo: "" } if (〈1;Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { userinfo: (〈2;Y〉.userinfo + "@") } host: 〈1;Y〉.host } Y: { if (〈1;#Y〉.userinfo != _|_(explicit error (_|_ literal) in source)) { userinfo: 〈2;#Y〉.userinfo } host: 〈1;#Y〉.host } #Y: 〈import;regexp〉.FindNamedSubmatch(〈1;#userHostPort〉, 〈0;X〉) Y: { userinfo: "user" host: "mod.test" } } } }