rantlr-core 0.2.0

Rantlr core: .gr lexer, parser, linter, and in-process runtime
Documentation
use std::fmt;

use crate::fix_hint::FixHint;
use crate::span::Span;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Severity {
    Error,
    Warning,
    Hint,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DiagnosticKind {
    LexError,
    ParseError,
    Lint,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Diagnostic {
    pub severity: Severity,
    pub kind: DiagnosticKind,
    pub message: String,
    pub span: Span,
    pub help: Option<String>,
    pub code: Option<String>,
    pub fix: Option<FixHint>,
}

impl fmt::Display for Diagnostic {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.message)
    }
}

impl Diagnostic {
    pub fn error(kind: DiagnosticKind, message: impl Into<String>, span: Span) -> Self {
        Self {
            severity: Severity::Error,
            kind,
            message: message.into(),
            span,
            help: None,
            code: None,
            fix: None,
        }
    }

    pub fn with_help(mut self, help: impl Into<String>) -> Self {
        self.help = Some(help.into());
        self
    }

    pub fn with_code(mut self, code: impl Into<String>) -> Self {
        self.code = Some(code.into());
        self
    }

    pub fn with_fix(mut self, fix: FixHint) -> Self {
        self.fix = Some(fix);
        self
    }

    pub fn format(&self, source: &str, file: &str) -> String {
        let (line, col) = self.span.line_col(source);
        let mut out = format!(
            "{file}:{line}:{col}: {:?}: {}",
            self.severity, self.message
        );
        if let Some(help) = &self.help {
            out.push_str("\n  help: ");
            out.push_str(help);
        }
        out
    }
}