Pattern(s) for end-of-iteration?

The standard iteration pattern is for a get-next-item function to return an optional item, thus:

pub fn next(self: Iterator) ?Item {...}

I am using that pattern to iterate over characters while implementing a Recursive Descent parser.

There is a common element that keeps falling out at me, however: my parsing involves a stream or sequence (of characters) that has sub-sequences contained in it that “end.” When these subsequences end, it could be the end of the iterator, or it could be … not. Like parsing a function, when you get the ‘}’ you don’t much care if the file ends, or if there is another function coming next.

So my code contains selection statements (if or switch) that check the contents of the next values, but my code also contains an end-of-iteration check. The result is that I keep doing this:

    if (input.next()) |value| {
        if (value == ... or value == ...) {  // if value in FOLLOW
            end_of_thing();
            return;
        }
        not_the_end_of_the_thing();
    }
    else {
        end_of_thing();
    }
    return;

Notice that I keep having to repeat the end_of_thing() code in two locations. I asked about switch being able to handle optional values, and apparently that was considered in a PR and rejected.

So does anyone have a useful pattern for dealing with this? Is there some clever Zig-ism that can help me work around this, or a trick with blocks, or something? I want to write DRY code, and it seems like this isn’t the way to do it.

Bueller?

Bueller?

Bueller?

Maybe this pattern may be a bit more logical?

while (true) {
   // Early return if no more input.
   const value = input.next() orelse return end_of_thing();

   // Now you know value has input; check if no need to continue.
   if (value == ... or value == ...) return end_of_thing();

   // Continue
   not_the_end_of_the_thing();
}

There is still some repetition here, but I think that’s almost unavoidable in a parser. Also I used returns but depending on the context they coud be breaks or continues.

3 Likes