use codespan_reporting::{ diagnostic::{Diagnostic, Label}, files::SimpleFiles, }; use crate::Span; #[derive(Debug)] pub struct Errors { pub kind: ErrorKind, pub locs: Vec, } #[derive(Debug)] pub enum ErrorKind { InvalidToken, SyntaxError(SyntaxErrorKind), CommandNotFound, } #[derive(Debug)] pub enum SyntaxErrorKind { /// `MissingStreamer` means, that the pipeline starts with a Pipe (`|`), so it has no streamer as input in front of it. MissingStreamer, /// `MissingSink` means, that the pipeline ends with a Pipe (`|`), meaning that the output can't go anywhere MissingSink, /// This indicates a missing filter somewhere in the pipeline, meaning that there's 2 pipes after one another MissingFilter, /// A literal cannot be a sink LiteralAsSink, /// A literal can't be a filter either LiteralAsFilter, /// A literal acting as streamer cannot take arguments LiteralWithArgs, } impl Errors { pub fn new(kind: ErrorKind, locs: Vec) -> Self { Self { kind, locs } } pub fn new_single(kind: ErrorKind, loc: Span) -> Self { Self { kind, locs: vec![loc], } } pub fn into_diag( &self, file_id: usize, _file_db: &SimpleFiles<&str, String>, ) -> Diagnostic { let Errors { kind, locs } = self; match kind { ErrorKind::InvalidToken => simple_diag(locs.clone(), file_id, "invalid tokens"), ErrorKind::SyntaxError(syntax_error) => match syntax_error { SyntaxErrorKind::MissingStreamer => simple_diag( locs.clone(), file_id, "pipeline is missing an input provider", ), SyntaxErrorKind::MissingSink => { simple_diag(locs.clone(), file_id, "pipeline is missing a sink") } SyntaxErrorKind::MissingFilter => { simple_diag(locs.clone(), file_id, "missing filters in pipeline") } SyntaxErrorKind::LiteralAsSink => { simple_diag(locs.clone(), file_id, "pipelines can't end in a literal") } SyntaxErrorKind::LiteralAsFilter => { simple_diag(locs.clone(), file_id, "literals can't filter data") } SyntaxErrorKind::LiteralWithArgs => { simple_diag(locs.clone(), file_id, "literals can't take arguments") } }, ErrorKind::CommandNotFound => simple_diag(locs.clone(), file_id, "command not found"), } } } fn simple_diag(spans: Vec, file_id: usize, msg: &str) -> Diagnostic { Diagnostic::error().with_message(msg).with_labels( spans .into_iter() .map(|span| Label::primary(file_id, span)) .collect(), ) }