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?