celestial_hub_astrolabe/parser/
mod.rs1use ariadne::ReportBuilder;
2use lalrpop_util::{lalrpop_mod, ParseError};
3
4use crate::{ast, lexer::Lexer};
5
6pub struct Parser;
7
8lalrpop_mod!(pub astrolabe_grammar, "/parser/grammar.rs");
9
10impl Parser {
11 pub fn new() -> Self {
12 Self
13 }
14
15 pub fn parse(&self, lexer: Lexer) -> Result<ast::Program, Box<dyn std::error::Error>> {
16 use ariadne::{Color, ColorGenerator, Config, Fmt, Label, Report, ReportKind, Source};
17
18 let mut colors = ColorGenerator::default();
19
20 let filename = lexer.filepath.split('/').last().unwrap();
21 let source = lexer.source_code;
22
23 let report: ReportBuilder<(&str, std::ops::Range<usize>)> =
24 Report::build(ReportKind::Error, filename, 12)
25 .with_code(3)
26 .with_config(Config::default().with_tab_width(2))
27 .with_note(format!(
28 "If you think this is a bug, please file an issue at {}",
29 "github.com/celestial-hub/compass/issues".fg(Color::Blue)
30 ));
31
32 match astrolabe_grammar::ProgramParser::new().parse(lexer) {
33 Ok(ast) => Ok(ast),
34 Err(err) => match err {
35 ParseError::InvalidToken { location } => {
36 report
37 .with_message("Invalid token".fg(Color::Red))
38 .with_label(
39 Label::new((filename, location..location))
40 .with_message("Invalid token")
41 .with_color(colors.next()),
42 )
43 .finish()
44 .print((filename, Source::from(source)))
45 .unwrap();
46
47 Err(Box::new(err))
48 }
49 ParseError::User { .. } => Err(Box::new(err)),
50 ParseError::UnrecognizedToken {
51 ref token,
52 ref expected,
53 } => {
54 report
55 .with_message("Unrecognized token".fg(Color::Red))
56 .with_label(
57 Label::new((filename, token.0..token.2))
58 .with_message("Unrecognized token")
59 .with_color(colors.next()),
60 )
61 .with_help(format!(
62 "Expected one of the following: {}",
63 expected
64 .iter()
65 .map(|token| {
66 let token = &token[1..token.len() - 1];
68
69 format!("{}", token.fg(Color::Yellow))
70 })
71 .collect::<Vec<String>>()
72 .join(", ")
73 ))
74 .finish()
75 .print((filename, Source::from(source)))
76 .unwrap();
77 Err(Box::new(err))
78 }
79 _ => Err(Box::new(err)),
80 },
81 }
82 }
83}
84
85impl Default for Parser {
86 fn default() -> Self {
87 Self::new()
88 }
89}