• Stars
    star
    255
  • Rank 159,729 (Top 4 %)
  • Language
    Haskell
  • License
    BSD 3-Clause "New...
  • Created over 4 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A simple library for reporting compiler/interpreter errors

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

  • Show diagnostics with/without 8-bit colors, with/without Unicode characters
  • Inline and multiline markers are nicely displayed
  • The order of markers matters! If there are multiple markers on the same line, they are ordered according to how they were put in each report
  • Reports spanning across multiple files are handled as well
  • Generic over the type of message which can be displayed, meaning that you can output custom data types as well as they can be pretty-printed
  • Diagnostics can be exported to JSON, if you don't quite like the rendering as it is, or if you need to transmit them to e.g. a website
  • Plug and play (mega)parsec integration and it magically works with your parsers!
  • Support for optional custom error codes, if you want to go the Rust way
  • Variable width Unicode characters are handled in a crossplatform manner
  • TAB characters have custom sizes specified when printing a diagnostic, so that you decide the width of a TAB, not your terminal emulator!
  • Colors can be tweaked thanks to the ability to export diagnostics as Documents

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:

  • Error reports, created through Err
  • Warning reports, created by using Warn

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:

  • A This marker indicates the main reason of the error. It is highlighted in red (for errors) or yellow (for warnings). Ideally, there is only one per report, but this isn't strictly required.
  • A Where marker adds additional context to the error by adding highlighted code to the error. This can be used to remind used that a variable was found of a given type earlier, or even where a previous declaration was found in another file. This is output in blue by default.
  • A Maybe marker is probably the rarest one. It is basically a way of suggesting fixes (as when GCC tells you that you probably mistyped a variable name). These markers are highlighted in green.

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:

  • print the diagnostic onto a file Handle (most likely stdout or stderr) using printDiagnostic;
  • create a Document which can be further altered using prettyDiagnostic;
  • or export it to JSON with diagnosticToJson or the ToJSON class of Aeson (the output format is documented under the diagnosticToJson function).

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.

More Repositories

1

nihil

Nihil, a statically typed interpreted functional programming language
Haskell
68
star
2

snowstar

Here lies the code for the Snow* programming language, currently being rewritten.
C++
33
star
3

hm-defense

A work-in-progress rewrite from scratch of the old iOS game "Heavy MACH: Defense"
Kotlin
30
star
4

jellyvm

A VM written following the Linear Abstract Machine architecture
Haskell
22
star
5

HaSM

An assembly language EDSL for Haskell, compiling into opcodes
Haskell
11
star
6

oneiric

A small kernel + OS based on how dreams work
C
10
star
7

coqide.kak

A fully-fledged CoqIDE-like experience for Kakoune
Rust
7
star
8

amethyst

A simple concatenative programming language
Haskell
6
star
9

bfhs

bf.hs, a small BrainFuck interpreter written in Haskell
Haskell
5
star
10

snowstar_old

Snow* was an old ASM-like language running on its own VM. It has not been updated since 1 year and will probably never again.
C++
5
star
11

snowstar-lang

This project is the `Snow*` "official" website.
CSS
4
star
12

nix-config

My home-manager config, for Nix/NixOS
Nix
4
star
13

paranet

Paranet is a little esoteric language runtime based on distributed computation.
Haskell
4
star
14

diagnose4j

A port of my Diagnose library for Java
Java
4
star
15

mini-noc

Playing around with very unsafe Haskell code
Haskell
3
star
16

blobot

A discord bot for running some blob code
Rust
2
star
17

snowstar-vscode

Syntax highlighter for Visual Studio Code for the Snow* programming language
2
star
18

isabelle.nix

Defines a Nix flake for Isabelle 2022
Nix
1
star
19

pixie

A simple, yet powerful, imperative language with a FFI
Haskell
1
star
20

tinyraytracer

A non-official fork of https://github.com/ssloy/tinyraytracer where the end goal is to add various stuff as a homework
C++
1
star