What are some approaches for gathering and conveying compiler errors
The simplest approach is just to throw an exception with error information at the first occurrence of an error. Perhaps another approach is to pass a mutable list argument through analysis functions. But I've noticed the F# compiler for example will accumulate errors incrementally in the Visual S开发者_运维技巧tudio error pane throughout compilation. Would using a TraceListener be an option? What are some pros and cons of different approaches.
I'm particularly interested in approaches for compilers targeting .NET using a functional language like F#, but would appreciate approaches (which may or may not be different) in other contexts as well.
You can always look at the F# compiler code as one example (though real-world code is always a bit of a mess :) ):
https://github.com/fsharp/fsharp/blob/master/src/fsharp/ErrorLogger.fs
We have an ErrorLogger interface with warning and error 'sinks', and various parts of the compiler 'sink' errors and warnings to the active logger via the interface.
It can be tough when encountering an error to decide whether you should throw (and abandon local control flow) or log-and-continue (to get more info but risk more cascade errors). There are lots of strategies to deal with this, but all end up being tricky, as your typical industrial-strength compiler has thousands of diagnostics and people can write incorrect code a seemingly infinite number of ways, and a one-size-fits-all solution is unlikely to provide the best experience for every error, or even every common error.
As someone said, compilers universally write output to stdout/stderr in a canonical format. MSBuild and Visual Studio parse the build output to light up the error list and squiggles in the IDE UI. For incremental feedback while typing (and not building), VS does also 'host' the front-end of the compiler in-process and read the error messages directly out of the 'sinks'.
So long as you at least have one abstraction boundary (e.g. a LogWarning
and LogError
function, which might even be global, just ensure all warnings/errors use it), then you're always in a position to refactor to meet changing needs/designs.
Any compiler I've used, including .NET ones, immediately types the error message to the console. Pretty important consideration is that this allows the programmer to type Ctrl+C to put a quick end to the slew of errors that are generated because of a mistake in a declaration. Not terribly relevant anymore these days but neither is doing it differently.
精彩评论