litcheck_filecheck/parse/
mod.rs

1mod lexer;
2mod parser;
3#[cfg(test)]
4mod tests;
5
6use crate::common::*;
7
8pub use self::lexer::{Lexed, Lexer, LexerError, Token};
9pub use self::parser::CheckFileParser;
10
11pub type ParseError<'a> = lalrpop_util::ParseError<usize, Token<'a>, ParserError>;
12
13#[derive(Diagnostic, Debug, thiserror::Error)]
14pub enum ParserError {
15    #[error(transparent)]
16    #[diagnostic(transparent)]
17    Lexer(#[from] LexerError),
18    #[error(transparent)]
19    #[diagnostic(transparent)]
20    Expr(#[from] crate::expr::ExprError),
21    #[error("invalid token")]
22    #[diagnostic()]
23    InvalidToken {
24        #[label("occurs here")]
25        span: SourceSpan,
26    },
27    #[error("unrecognized token")]
28    #[diagnostic(help("expected one of: {}", expected.as_slice().join(", ")))]
29    UnrecognizedToken {
30        #[label("lexed a {token} here")]
31        span: SourceSpan,
32        token: String,
33        expected: Vec<String>,
34    },
35    #[error("unexpected trailing tokens")]
36    #[diagnostic()]
37    ExtraToken {
38        #[label("{token} was found here, but was not expected")]
39        span: SourceSpan,
40        token: String,
41    },
42    #[error("unexpected end of file")]
43    #[diagnostic(help("expected one of: {}", expected.as_slice().join(", ")))]
44    UnrecognizedEof {
45        #[label("reached end of file here")]
46        span: SourceSpan,
47        expected: Vec<String>,
48    },
49    #[error("invalid check type")]
50    #[diagnostic()]
51    InvalidCheckType {
52        #[label("this is not a valid check type")]
53        span: SourceSpan,
54    },
55    #[error("invalid pattern")]
56    #[diagnostic(help("CHECK-EMPTY should be used to check for empty lines"))]
57    EmptyPattern {
58        #[label("expected a non-empty pattern")]
59        span: SourceSpan,
60    },
61    #[error("invalid check modifier")]
62    #[diagnostic()]
63    InvalidCheckModifier {
64        #[label("this modifier is not recognized, valid modifiers are: LITERAL")]
65        span: SourceSpan,
66    },
67    #[error("unclosed substitution block")]
68    #[diagnostic()]
69    UnclosedSubstitution {
70        #[label("no closing ']]' found for this block")]
71        span: SourceSpan,
72    },
73    #[error("unclosed regex block")]
74    #[diagnostic()]
75    UnclosedRegex {
76        #[label("no closing '}}' found for this block")]
77        span: SourceSpan,
78    },
79    #[error("no check strings found with prefix(es) {}", text::DisplayCommaSeparated(.0.as_slice()))]
80    #[diagnostic()]
81    UnusedCheckPrefixes(Vec<Arc<str>>),
82}
83
84pub type ParseResult<T> = Result<T, ParserError>;
85
86pub trait Parser<'parser> {
87    type Value<'a>
88    where
89        'a: 'parser;
90
91    fn parse<'a: 'parser, S>(&mut self, code: &'a S) -> ParseResult<Self::Value<'a>>
92    where
93        S: SourceFile + ?Sized + 'a;
94}