How do you split large, messy loops into functions?

I'm writing a Pratt parser, which essentially takes the form of

loop {
  match thing {
    a => ... if foo {break} ...,
    b => ... if bar {break} ...,
  }
}

Where each ... is some long, ugly mess of spaghetti code.

My solution so far has been this janky thing:

struct LoopResult<T> {
    value: T,
    r#break: bool,
    r#continue: bool,
}

impl<T> LoopResult<T> {
    fn r#break(value: T) -> Self {
        Self {
            value,
            r#break: true,
            r#continue: false,
        }
    }

    fn r#continue(value: T) -> Self {
        Self {
            value,
            r#break: false,
            r#continue: true,
        }
    }
}

loop {
    match thing {
        a => {
            let t = foo();

            if t.break {break;}

            return t.value
        }
    }
}

but this isn't ideal for a few reasons. Have any of y'all discovered a good way to avoid this style of code?

I'm not sure how you're using LoopResult, but it's quite close to ControlFlow.

9 Likes

Oh, that's perfect! Thank you. My "solution" seemed a little dubious, so I'm much happier to use an actual crate (edit: std library, actually!) for this functionality.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.