1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! Compilation error handling
//!
//! Exports the default Result type which is used throughout the compiler

use annotate_snippets::display_list::DisplayList;
use debris_common::CompileContext;

use itertools::Itertools;
pub use lang_error::{ControlFlowRequires, LangError, LangErrorKind};
pub use parse_error::ParseError;
pub use snippet::{SliceOwned, SnippetOwned, SourceAnnotationOwned};

mod utils;

mod lang_error;
mod macros;
mod parse_error;
mod snippet;

/// Used to determine whether the error messages should use console colors
/// Or be plain text
pub const COLORED: bool = cfg!(feature = "colored_errors");

/// The result type used by most of the core functions
pub type Result<T> = std::result::Result<T, SingleCompileError>;

/// A result type which allows quick error throwing since no span and other boilerplate is needed
pub type LangResult<T> = std::result::Result<T, LangErrorKind>;

pub trait AsAnnotationSnippet<'a> {
    fn as_annotation_snippet(&self, ctx: &'a CompileContext) -> SnippetOwned<'a>;

    fn to_display_list(&self, ctx: &'a CompileContext) -> String {
        let snippet = self.as_annotation_snippet(ctx);
        let display_list = DisplayList::from(snippet.as_snippet(&ctx.input_files));
        display_list.to_string()
    }
}

#[derive(Debug)]
pub struct CompileErrors(pub Vec<SingleCompileError>);

impl CompileErrors {
    pub fn format(&self, ctx: &CompileContext) -> String {
        self.0.iter().map(|error| error.format(ctx)).join("\n\n")
    }
}

impl From<Vec<SingleCompileError>> for CompileErrors {
    fn from(errors: Vec<SingleCompileError>) -> Self {
        CompileErrors(errors)
    }
}

/// A Compile Error
///
/// This type is the Err value for most of this crate.
/// It is compatible with the `annotate_snippets` library.
/// That means that nice rust-style error messages can be printed.
#[derive(Debug)]
pub enum SingleCompileError {
    /// An error which happens when parsing the input
    ParseError(Box<ParseError>),
    /// An error which happens when compiling the input
    LangError(Box<LangError>),
}

impl SingleCompileError {
    pub fn format(&self, ctx: &CompileContext) -> String {
        <Self as AsAnnotationSnippet>::to_display_list(self, ctx)
    }
}

impl From<ParseError> for SingleCompileError {
    fn from(parse_error: ParseError) -> Self {
        SingleCompileError::ParseError(Box::new(parse_error))
    }
}

impl From<LangError> for SingleCompileError {
    fn from(lang_error: LangError) -> Self {
        SingleCompileError::LangError(Box::new(lang_error))
    }
}

impl<'a> AsAnnotationSnippet<'a> for SingleCompileError {
    fn as_annotation_snippet(&self, ctx: &'a CompileContext) -> SnippetOwned<'a> {
        match self {
            SingleCompileError::ParseError(parse_error) => parse_error.as_annotation_snippet(ctx),
            SingleCompileError::LangError(lang_error) => lang_error.as_annotation_snippet(ctx),
        }
    }
}