Home

Awesome

Error reporting made easy

Diagnose is a small library used to report compiler/interpreter errors in a beautiful yet readable way. It was in the beginning heavily inspired by ariadne, but ended up quickly becoming its own thing.

As a great example, here's the output of the last test:

first example

If you do not like unicode characters, or choose to target platforms which cannot output them natively; you may alternatively print the whole diagnostic with ASCII characters, like this:

second example

Colors are also optional, and you may choose not to print them.

Features

Usage

You only need to import Error.Diagnose, and everything should be ready to go. You don't even need to import Prettyprinter, as it is already provided to you by Error.Diagnose!


A diagnostic can be viewed as a collection of reports, spanning on files. This is what the Diagnostic type embodies.

It is an instance of Monoid, which can be used to construct an empty diagnostic (contains no reports, and has no files).

The second step is to add some reports. There are two kinds of reports:

Both of these fonctions have the following type:

-- | An optional error code, shown right after @error@ or @warning@ in the square brackets
Maybe msg ->
-- | The main message, which is output at the top right after @[error]@ or @[warning]@
msg ->
-- | A list of markers, along with the positions they span on
[(Position, Marker msg)] ->
-- | Some hints to be output at the bottom of the report
[Note msg] ->
-- | The created report
Report msg

Each report contains markers, which are what underlines the code in the screenshots above. They come in three flavors:

The Position datatype is however required to be used with this library. If you use another way of keeping track of position information, you will need to convert them to the Position datatype.

Once your reports are created, you will need to add them inside the diagnostic using addReport. You will also need to put your files into the diagnostic with addFile, else lines won't be printed and you will get <no-line> in your reports.

After all of this is done, you may choose to either:

Example

Here is how the above screenshot was generated:

let beautifulExample =
      err
        Nothing
        "Could not deduce constraint 'Num(a)' from the current context"
        [ (Position (1, 25) (2, 6) "somefile.zc", This "While applying function '+'"),
          (Position (1, 11) (1, 16) "somefile.zc", Where "'x' is supposed to have type 'a'"),
          (Position (1, 8) (1, 9) "somefile.zc", Where "type 'a' is bound here without constraints")
        ]
        ["Adding 'Num(a)' to the list of constraints may solve this problem."]
        -- ^^^^ This is a 'Note' not a 'Hint', as specified by its 'IsString' instance

-- Create the diagnostic
let diagnostic  = addFile mempty "somefile.zc" "let id<a>(x : a) : a := x\n  + 1"
let diagnostic' = addReport diagnostic beautifulExample

-- Print with unicode characters, and the default (colorful) style
printDiagnostic stdout WithUnicode 4 defaultStyle diagnostic'

More examples are given in the test/rendering folder (execute stack test to see the output).

TODO list

<< empty, for now >>

License

This work is licensed under the BSD-3 clause license.

Copyright (c) 2021-2022 Mesabloo, all rights reserved.