I’ve been working on improving error handling in meta# for the last couple of weeks. Previously there was no support and basically your code would either parse correctly or it would not.
So I cracked open the Purple Dragon book, dug into Martin Fowlers DSL book, asked on the OMeta forums and read about how some other grammar tools do error handling.
It would probably have helped to have someone sit down and show me but I had a real hard time understanding exactly what the various solutions were. But other than not fully getting the specifics I think I got the general idea and was able to add two new error handling semantics to meta#.
Parsing errors basically all boil down to a single type of problem: the thing that is next in the stream is not what you were expecting. I decided that you could look at this problem two different ways. You could either say that something you expect is missing or something you didn’t expect is present.
So I added two new pattern semantics “error unless X” and “error until X”, where X is any pattern.
In the case of “error unless”, that is like saying something you expected is missing. In this case an error will be logged, input from the stream will not be consumed and null will be returned rather than fail. This will let whatever rule that uses these semantics to still project and give you a very specific message and if the following code is well formed the parser could even recover without any additional errors. This is very useful for missing ‘;’ at the end of statements.
For “error until”, it is like saying something you were not expecting is present. In this case all of the input will be consumed until the X pattern is matched. An error will be reported and fail will be returned. This is very good for sync’ing to the next close bracket because it will read all unknown input and treat it as an error.
One last way to report errors is just by calling context.LogError(…) from within a projection. Then you can handle more complex cases and log arbitrary error messages. I might have to expand the api for this but here is an example of how I’m using it so far.