收集和传达编译器错误的方法有哪些
最简单的方法是在第一次发生错误时抛出带有错误信息的异常。也许另一种方法是通过分析函数传递可变列表参数。但我注意到,例如 F# 编译器会在整个编译过程中在 Visual Studio 错误窗格中逐渐累积错误。使用 TraceListener 是一种选择吗?不同方法的优点和缺点是什么?
我对使用 F# 等函数式语言针对 .NET 的编译器的方法特别感兴趣,但也很欣赏其他上下文中的方法(可能会或可能不会不同)。
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 Studio 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我使用过的任何编译器(包括 .NET 编译器)都会立即在控制台中键入错误消息。非常重要的考虑因素是,这允许程序员键入 Ctrl+C 来快速结束由于声明错误而生成的大量错误。如今已经不再那么重要了,但做法也没有什么不同。
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.
您始终可以将 F# 编译器代码作为示例(尽管现实世界的代码总是有点混乱:)):
https://github.com/fsharp/fsharp/blob/master/src/fsharp/ErrorLogger.fs
我们有一个ErrorLogger 接口具有警告和错误“接收器”,编译器的各个部分通过该接口将错误和警告“接收”到活动记录器。
遇到错误时,决定是否应该抛出(并放弃本地控制流)或记录并继续(以获取更多信息,但冒更多级联错误的风险)可能很困难。有很多策略可以解决这个问题,但最终都变得很棘手,因为典型的工业强度编译器有数千个诊断,人们可以通过看似无数的方式编写不正确的代码,并且一刀切解决方案不可能为每个错误甚至每个常见错误提供最佳体验。
正如有人所说,编译器普遍以规范格式将输出写入 stdout/stderr。 MSBuild 和 Visual Studio 解析构建输出以点亮 IDE UI 中的错误列表和波形曲线。为了在键入(而不是构建)时获得增量反馈,VS 还会在进程中“托管”编译器的前端,并直接从“接收器”中读取错误消息。
只要您至少有一个抽象边界(例如 LogWarning 和 LogError 函数,甚至可能是全局的,只需确保所有警告/错误都使用它),那么您始终能够进行重构以满足不断变化的需求/设计。
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
andLogError
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.