esl_compiler/
parser.rs

1//! Pest parser implementation for the Elephant Specification Language (ESL).
2use pest::iterators::Pairs;
3use pest::Parser;
4use pest_derive::Parser;
5use snafu::{ResultExt, Snafu};
6
7use crate::diagnostics::DiagnosticError;
8use crate::location::Uri;
9
10/// Hard failure error type for the Elephant Specification Language (ESL) parser.
11#[derive(Clone, Debug, PartialEq, Snafu)]
12pub enum Error {
13    /// An error thrown by the Pest parser used internally.
14    PestError {
15        source: Box<pest::error::Error<Rule>>,
16    },
17}
18impl Error {
19    /// Parsing error's range.
20    pub fn as_range(&self) -> lsp_types::Range {
21        match self {
22            Error::PestError { source } => match source.line_col {
23                pest::error::LineColLocation::Pos((line, col)) => {
24                    let pos = lsp_types::Position {
25                        line: line as u32 - 2,
26                        character: col as u32 - 1,
27                    };
28                    lsp_types::Range {
29                        start: pos,
30                        end: pos,
31                    }
32                }
33                pest::error::LineColLocation::Span(
34                    (start_line, start_col),
35                    (end_line, end_col),
36                ) => lsp_types::Range {
37                    start: lsp_types::Position {
38                        line: start_line as u32 - 1,
39                        character: start_col as u32 - 1,
40                    },
41                    end: lsp_types::Position {
42                        line: end_line as u32 - 1,
43                        character: end_col as u32 - 1,
44                    },
45                },
46            },
47        }
48    }
49    /// Create related information for this error.
50    pub fn as_related_information(&self, uri: &Uri) -> lsp_types::DiagnosticRelatedInformation {
51        match self {
52            Self::PestError { source } => lsp_types::DiagnosticRelatedInformation {
53                message: format!("Pest parser error: {:?}", source),
54                location: lsp_types::Location {
55                    range: self.as_range(),
56                    uri: uri.as_ref().to_owned(),
57                },
58            },
59        }
60    }
61    /// Create a diagnostic from this error.
62    pub fn as_diagnostic(&self, uri: &Uri) -> lsp_types::Diagnostic {
63        let range = self.as_range();
64        let related_information = self.as_related_information(uri);
65        DiagnosticError::Internal.diagnostic(range, Some(vec![related_information]))
66    }
67}
68
69/// Pest parser that parses Elephant Specification Language (ESL) text.
70#[derive(Parser)]
71#[grammar = "grammar.pest"]
72pub struct ElephantParser;
73
74/// Parse text contents.
75pub fn parse_file_text(text: &str) -> Result<Pairs<'_, Rule>, Error> {
76    ElephantParser::parse(Rule::file, text)
77        .map_err(Box::new)
78        .with_context(|_| PestSnafu)
79}