A fancy diagnostics library that allows your compilers to exit with grace
Grace is an OCaml 🐪 library that includes a series of interfaces for building, reporting, and rendering beautiful compiler errors 📜.
We're still actively working on Grace to support more use cases and improving the quality of the rendering engine. Contributions are very welcome!
- 📐 Inline and multi-line error messages with associated priorities
- 📂 Multi-file errors
- ⚙️ Configurable rendering (styling and character set)
- 💰 Rich and compact error rendering
- 🌈 Colored messages (thanks to
Fmt
'sstyle
) for ANSI terminals - 💪 Written in OCaml
- 🔠 Unicode support
- 💯 Error codes
- LSP integration
- Accessibility features (improved color options, narratable renderers)
- HTML renderer
This library is available on opam
. To install
opam install grace
Users of dune
can then use this library by adding the appropriate libraries:
(library
...
(libraries grace grace.rendering ...))
open! Grace
(* Grace provides a [Source] API for in-memory representations of sources/files. *)
let fizz : Source.t =
`String
{ name = Some "fizz.ml"
; content =
{|
let fizz n =
match n mod 5, n mod 3 with
| 0, 0 -> `Fizz_buzz
| 0, _ -> `Fizz
| _, 0 -> `Buzz
| _, _ -> n
;;
|}
}
;;
(* Grace provides support for error codes.
Error codes are arbitrary types with an explicit [code_to_string] function
which converts the code into a short (googlable) error code. This allows
library users to inspect (and match on) certain types of diagnostics. *)
type code = Incompatible_types
let code_to_string = function
| Incompatible_types -> "E001"
;;
(* Normally locations (ranges) would be taken from AST nodes, but for sake of
this example we construct them directly. *)
let diagnostic =
let range start stop =
Range.create ~source:fizz (Byte_index.of_int start) (Byte_index.of_int stop)
in
Diagnostic.(
createf
~labels:
Label.
[ primaryf
~range:(range 116 117)
"expected `[> `Buzz | `Fizz | `Fizz_buzz]`, found `int`"
; secondaryf ~range:(range 17 117) "`match` cases have incompatible types"
; secondaryf ~range:(range 57 67) "this is found to be of type `[> `Fizz_buzz]`"
; secondaryf ~range:(range 80 85) "this is found to be of type `[> `Fizz]`"
; secondaryf ~range:(range 98 103) "this is found to be of type `[> `Buzz]`"
]
~code:Incompatible_types
Error
"`match` cases have incompatible types")
;;
let () =
Format.printf
"%a@."
Grace_ansi_renderer.(pp_diagnostic ())
diagnostic
;;
Authors:
- Alistair O'Brien (
@johnyob
)
grace
was heavily inspired by all the work on compiler diagnostics in the Rust ecosystem:
@brendanzab
for thecodespan
crate which heavily influenced the design ofgrace
's rendering engine.ariadne
(@zesterer
) for pushing the boundary on diagnostic rendering.rustc
and@estebank
's work on the state-of-the-art work on compiler diagnostics
This code is free, under the MIT license.