1use 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#[derive(Clone, Debug, PartialEq, Snafu)]
12pub enum Error {
13 PestError {
15 source: Box<pest::error::Error<Rule>>,
16 },
17}
18impl Error {
19 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 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 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#[derive(Parser)]
71#[grammar = "grammar.pest"]
72pub struct ElephantParser;
73
74pub 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}