rush_analyzer/
lib.rs

1#[macro_use]
2mod macros;
3
4mod analyzer;
5pub mod ast;
6mod diagnostic;
7
8use std::iter;
9
10pub use analyzer::*;
11use ast::AnalyzedProgram;
12pub use diagnostic::*;
13
14pub use rush_parser::ast::{AssignOp, InfixOp, PrefixOp, Type};
15use rush_parser::{Lexer, Parser};
16
17/// Analyzes rush source code and returns an analyzed (annotated) AST.
18/// The `Ok(_)` variant also returns non-error diagnostics.
19/// However, the `Err(_)` variant returns a `Vec<Diagnostic>` which contains at least one error
20pub fn analyze<'src>(
21    text: &'src str,
22    path: &'src str,
23) -> Result<(AnalyzedProgram<'src>, Vec<Diagnostic<'src>>), Vec<Diagnostic<'src>>> {
24    let lexer = Lexer::new(text, path);
25
26    let parser = Parser::new(lexer);
27    let (ast, errs) = parser.parse();
28
29    match (ast, errs.len()) {
30        (Err(critical), _) => Err(errs
31            .into_iter()
32            .map(Diagnostic::from)
33            .chain(iter::once((*critical).into()))
34            .collect()),
35        (Ok(ast), _) => {
36            let analyzer = Analyzer::new(text);
37
38            // saves potential issues of the parser as diagnostics
39            let mut parser_diagnostics: Vec<Diagnostic> =
40                errs.into_iter().map(Diagnostic::from).collect();
41
42            let (analyzed_ast, mut analyzer_diagnostics) = match analyzer.analyze(ast) {
43                Ok(res) => res,
44                Err(mut analyzer_diagnostics) => {
45                    parser_diagnostics.append(&mut analyzer_diagnostics);
46                    return Err(parser_diagnostics);
47                }
48            };
49
50            // append the analyzer diagnostics to the parser errors
51            parser_diagnostics.append(&mut analyzer_diagnostics);
52
53            // return the `Err(_)` variant if the diagnostics contain at least 1 error
54            match parser_diagnostics
55                .iter()
56                .any(|diagnostic| matches!(diagnostic.level, DiagnosticLevel::Error(_)))
57            {
58                true => Err(parser_diagnostics),
59                false => Ok((analyzed_ast, parser_diagnostics)),
60            }
61        }
62    }
63}