Swift Regex Builder issue

Why does this Regex Builder code in my SwiftUI app not work? I'm parsing a string that might be a date and time with either AM or PM specified for the time. This bit of code looks for the optional AM or PM.

The error I get is: The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

What would 'distinct sub-expressions' mean in this case?

The code:

    let ampmRef = Reference<Substring>()
    let ampmReg = Regex {
        Capture(as: ampmRef) {
            ZeroOrMore {
                ChoiceOf {
                    One("am")
                    One("pm")
                }
            }
        } transform: {
            $0.lowercase
        }
    }.ignoresCase()

In a related question, is there a way to return a default if the ChoiceOf fails both AM and PM?

I just noticed that I could make the error go away if I remove the transform. But why does that matter. I still don't understand that error message.

Your code has an innocuous error and that error is causing the compiler to go off into the weeds, eventually resulting in a very unhelpful diagnostic. Lemme explain the error itself, after which I’ll talk about how I found it.

The error relates to this line:

$0.lowercase

Here $0 is a Substring, and that has no lowercase property. You want the lowercased() method. So, this code compiles:

import Foundation
import RegexBuilder

func main() {
    let ampmRef = Reference<String>()
    let ampmReg = Regex {
        Capture(as: ampmRef) {
            ZeroOrMore {
                ChoiceOf {
                    One("am")
                    One("pm")
                }
            }
        } transform: {
            $0.lowercased()
        }
    }.ignoresCase()
    print(ampmReg)
}

main()

Note I had to change the type of ampmRef to match the result of lowercased().


As to how I found this, my experience is when you hit an error like this it’s best to radically simplify your code until you either get things compiling or your get a better error. If you get an error, you can investigate that. OTOH, if it starts to compile without error, you can add stuff back in slowly until things start to fail again.

In your example, I commented out the bulk of what’s inside the Capture and got this error:

import Foundation
import RegexBuilder

func main() {
    let ampmRef = Reference<Substring>()
    let ampmReg = Regex {
        Capture(as: ampmRef) {
//            ZeroOrMore {
//                ChoiceOf {
                    One("am")
//                    One("pm")
//                }
//            }
        } transform: {
            $0.lowercase
            // ^ Value of type 'Regex<One<String.RegexOutput>.RegexOutput>.RegexOutput' (aka 'Substring') has no member 'lowercase'
        }
    }.ignoresCase()
    print(ampmReg)
}

main()

Clearly the compiler should be better about this, and I encourage you to file a bug about your example.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Good example to learn from. Thanks @RJStover and @DTS Engineer !

Swift Regex Builder issue
 
 
Q