ola_parser/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! ola file parser
4
5pub mod diagnostics;
6pub mod program;
7use diagnostics::Diagnostic;
8use lalrpop_util::{lexer::Token, ParseError};
9use program::Loc;
10#[cfg(test)]
11mod test;
12
13#[allow(clippy::all)]
14mod ola {
15    include!(concat!(env!("OUT_DIR"), "/ola.rs"));
16}
17
18/// Parse Ola file
19pub fn parse(src: &str, file_no: usize) -> Result<program::SourceUnit, Vec<Diagnostic>> {
20    let parser_errors = &mut Vec::new();
21    let errors = &mut Vec::new();
22
23    let s = ola::SourceUnitParser::new().parse(file_no, parser_errors, src);
24
25    for e in parser_errors {
26        errors.push(parser_error(&e.error, file_no));
27    }
28
29    if let Err(e) = s {
30        errors.push(parser_error(&e, file_no));
31        return Err(errors.to_vec());
32    }
33
34    if !errors.is_empty() {
35        Err(errors.to_vec())
36    } else {
37        Ok(s.unwrap())
38    }
39}
40
41fn parser_error(error: &ParseError<usize, Token, &str>, file_no: usize) -> Diagnostic {
42    match &error {
43        ParseError::InvalidToken { location } => Diagnostic::parser_error(
44            Loc::File(file_no, *location, *location),
45            "invalid token".to_string(),
46        ),
47        ParseError::UnrecognizedToken {
48            token: (l, token, r),
49            expected,
50        } => Diagnostic::parser_error(
51            Loc::File(file_no, *l, *r),
52            format!(
53                "unrecognised token '{}', expected {}",
54                token,
55                expected.join(", ")
56            ),
57        ),
58        ParseError::User { error } => {
59            Diagnostic::parser_error(Loc::File(file_no, 0, 0), error.to_string())
60        }
61        ParseError::ExtraToken { token } => Diagnostic::parser_error(
62            Loc::File(file_no, token.0, token.2),
63            format!("extra token '{}' encountered", token.0),
64        ),
65        ParseError::UnrecognizedEOF { expected, location } => Diagnostic::parser_error(
66            Loc::File(file_no, *location, *location),
67            format!("unexpected end of file, expecting {}", expected.join(", ")),
68        ),
69    }
70}