boseiju/parser/
error.rs

1use crate::parser::ParserNode;
2use idris::Idris;
3
4/// Errors that can be thrown by the parser.
5#[derive(Debug, Clone)]
6pub enum ParserError {
7    UnexpectedToken {
8        found: FoundToken,
9        expecting: Vec<PossibleExpectedToken>,
10    },
11    FailedToApplyRule {
12        merge_error: &'static str,
13        for_rule: crate::parser::rules::ParserRuleDeclarationLocation,
14    },
15    InvalidEarleyTable,  /* Fixme: this shall never happen I think */
16    AmbiguousCandidates, /* Fixme: is this ever appears, we have problems ? */
17}
18
19impl ParserError {
20    pub(super) fn from_earley_table(table: &super::EarleyTable, tokens: &[crate::lexer::tokens::Token]) -> Self {
21        let error_row = table.table.iter().enumerate().rev().find(|(_, row)| !row.is_empty());
22        let (stuck_index, last_non_empty_row) = match error_row {
23            Some(error) => error,
24            None => return Self::InvalidEarleyTable,
25        };
26
27        let stuck_on_token = match tokens.get(stuck_index) {
28            Some(token) => FoundToken {
29                name: ParserNode::name_from_id(ParserNode::from(token.clone()).id()),
30                #[cfg(feature = "spanned_tree")]
31                position: token.span().start,
32                #[cfg(feature = "spanned_tree")]
33                length: token.span().end - token.span().start,
34            },
35            None => FoundToken {
36                name: "EOF",
37                #[cfg(feature = "spanned_tree")]
38                position: match tokens.last() {
39                    Some(last) => last.span().end,
40                    None => 0,
41                },
42                #[cfg(feature = "spanned_tree")]
43                length: 0,
44            },
45        };
46
47        /* Build a list of possible expected tokens (use a set to avoid repetitions) */
48        let mut expecting = std::collections::HashSet::new();
49        for (expecting_token, for_nodes) in last_non_empty_row.uncompleted_items.iter() {
50            /* Only take in terminal tokens ? */
51            use idris::Idris;
52            if *expecting_token < crate::lexer::tokens::Token::COUNT {
53                expecting.insert(PossibleExpectedToken {
54                    expected: *expecting_token,
55                    for_nodes: for_nodes
56                        .iter()
57                        .map(|item| (item.rule.merged, item.rule.creation_loc.clone()))
58                        .collect(),
59                });
60            }
61        }
62
63        Self::UnexpectedToken {
64            found: stuck_on_token,
65            expecting: expecting.into_iter().collect(),
66        }
67    }
68}
69
70impl std::fmt::Display for ParserError {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72        match self {
73            Self::UnexpectedToken { found, expecting } => {
74                #[cfg(feature = "spanned_tree")]
75                write!(
76                    f,
77                    "Unexpected token at position {}, length {}: \"{}\"",
78                    found.position, found.length, found.name,
79                )?;
80                #[cfg(not(feature = "spanned_tree"))]
81                write!(f, "Unexpected token: \"{}\"", found.name,)?;
82                if !expecting.is_empty() {
83                    write!(f, "\nExpecting one of:")?;
84                    for expecting in expecting.iter().take(10) {
85                        let node_name = <ParserNode as idris::Idris>::name_from_id(expecting.expected);
86                        write!(f, "\n - token \"{node_name}\" to create nodes")?;
87                        for (i, (for_node, for_rule)) in expecting.for_nodes.iter().take(3).enumerate() {
88                            let node_name = <ParserNode as idris::Idris>::name_from_id(*for_node);
89                            if i == 0 {
90                                write!(f, " \"{node_name}\" (at {for_rule})")?;
91                            } else {
92                                write!(f, ", \"{node_name}\" (at {for_rule})")?;
93                            }
94                        }
95                        if expecting.for_nodes.len() > 3 {
96                            write!(f, "And {} others", expecting.for_nodes.len() - 10)?;
97                        }
98                    }
99                    if expecting.len() > 10 {
100                        write!(f, "\nAnd {} others", expecting.len() - 10)?;
101                    }
102                } else {
103                    write!(f, "\nNo tokens were expected !")?;
104                }
105            }
106            Self::FailedToApplyRule { merge_error, for_rule } => {
107                write!(f, "Failed to use rule (declared at: {}): {}", for_rule, merge_error)?;
108            }
109            Self::InvalidEarleyTable => write!(f, "Empty Earley table !")?,
110            Self::AmbiguousCandidates => write!(f, "Multiple candidates for rule completion !")?,
111        }
112
113        Ok(())
114    }
115}
116
117impl std::error::Error for ParserError {}
118
119#[derive(Debug, Clone, PartialEq, Eq, Hash)]
120pub struct PossibleExpectedToken {
121    pub expected: usize,
122    pub for_nodes: Vec<(usize, crate::parser::rules::ParserRuleDeclarationLocation)>,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, Hash)]
126pub struct FoundToken {
127    pub name: &'static str,
128    #[cfg(feature = "spanned_tree")]
129    pub position: usize,
130    #[cfg(feature = "spanned_tree")]
131    pub length: usize,
132}