1use std::fmt;
2
3use compact_str::{CompactString, format_compact};
4use derive_more::with_trait::{Display, Error};
5
6use crate::parser::{Lexer, LexerError, Spanning, Token};
7
8#[derive(Clone, Debug, Display, Eq, Error, PartialEq)]
10pub enum ParseError {
11 #[display("Unexpected \"{_0}\"")]
15 UnexpectedToken(#[error(not(source))] CompactString),
16
17 #[display("Unexpected end of input")]
19 UnexpectedEndOfFile,
20
21 LexerError(LexerError),
23
24 ExpectedScalarError(#[error(not(source))] &'static str),
26}
27
28impl ParseError {
29 #[must_use]
31 pub fn unexpected_token(token: Token<'_>) -> Self {
32 Self::UnexpectedToken(format_compact!("{token}"))
33 }
34}
35
36#[doc(hidden)]
37pub type ParseResult<T> = Result<Spanning<T>, Spanning<ParseError>>;
38
39#[doc(hidden)]
40pub type UnlocatedParseResult<T> = Result<T, Spanning<ParseError>>;
41
42#[doc(hidden)]
43pub type OptionParseResult<T> = Result<Option<Spanning<T>>, Spanning<ParseError>>;
44
45#[doc(hidden)]
46#[derive(Debug)]
47pub struct Parser<'a> {
48 tokens: Vec<Spanning<Token<'a>>>,
49}
50
51impl<'a> Parser<'a> {
52 #[doc(hidden)]
53 pub fn new(lexer: &mut Lexer<'a>) -> Result<Parser<'a>, Spanning<LexerError>> {
54 let mut tokens = Vec::new();
55
56 for res in lexer {
57 match res {
58 Ok(s) => tokens.push(s),
59 Err(e) => return Err(e),
60 }
61 }
62
63 Ok(Parser { tokens })
64 }
65
66 #[doc(hidden)]
67 pub fn peek(&self) -> &Spanning<Token<'a>> {
68 &self.tokens[0]
69 }
70
71 #[doc(hidden)]
72 pub fn next_token(&mut self) -> ParseResult<Token<'a>> {
73 if self.tokens.len() == 1 {
74 Err(Spanning::new(
75 self.peek().span,
76 ParseError::UnexpectedEndOfFile,
77 ))
78 } else {
79 Ok(self.tokens.remove(0))
80 }
81 }
82
83 #[doc(hidden)]
84 pub fn expect(&mut self, expected: &Token) -> ParseResult<Token<'a>> {
85 if &self.peek().item != expected {
86 Err(self.next_token()?.map(ParseError::unexpected_token))
87 } else {
88 self.next_token()
89 }
90 }
91
92 #[doc(hidden)]
93 pub fn skip(
94 &mut self,
95 expected: &Token,
96 ) -> Result<Option<Spanning<Token<'a>>>, Spanning<ParseError>> {
97 if &self.peek().item == expected {
98 Ok(Some(self.next_token()?))
99 } else if self.peek().item == Token::EndOfFile {
100 Err(Spanning::zero_width(
101 &self.peek().span.start,
102 ParseError::UnexpectedEndOfFile,
103 ))
104 } else {
105 Ok(None)
106 }
107 }
108
109 #[doc(hidden)]
110 pub fn delimited_list<T, F>(
111 &mut self,
112 opening: &Token,
113 parser: F,
114 closing: &Token,
115 ) -> ParseResult<Vec<Spanning<T>>>
116 where
117 T: fmt::Debug,
118 F: Fn(&mut Parser<'a>) -> ParseResult<T>,
119 {
120 let start_pos = &self.expect(opening)?.span.start;
121 let mut items = Vec::new();
122
123 loop {
124 if let Some(Spanning { span, .. }) = self.skip(closing)? {
125 return Ok(Spanning::start_end(start_pos, &span.end, items));
126 }
127
128 items.push(parser(self)?);
129 }
130 }
131
132 #[doc(hidden)]
133 pub fn delimited_nonempty_list<T, F>(
134 &mut self,
135 opening: &Token,
136 parser: F,
137 closing: &Token,
138 ) -> ParseResult<Vec<Spanning<T>>>
139 where
140 T: fmt::Debug,
141 F: Fn(&mut Parser<'a>) -> ParseResult<T>,
142 {
143 let start_pos = &self.expect(opening)?.span.start;
144 let mut items = Vec::new();
145
146 loop {
147 items.push(parser(self)?);
148
149 if let Some(end_spanning) = self.skip(closing)? {
150 return Ok(Spanning::start_end(start_pos, &end_spanning.end(), items));
151 }
152 }
153 }
154
155 #[doc(hidden)]
156 pub fn unlocated_delimited_nonempty_list<T, F>(
157 &mut self,
158 opening: &Token,
159 parser: F,
160 closing: &Token,
161 ) -> ParseResult<Vec<T>>
162 where
163 T: fmt::Debug,
164 F: Fn(&mut Parser<'a>) -> UnlocatedParseResult<T>,
165 {
166 let start_pos = &self.expect(opening)?.span.start;
167 let mut items = Vec::new();
168
169 loop {
170 items.push(parser(self)?);
171
172 if let Some(end_spanning) = self.skip(closing)? {
173 return Ok(Spanning::start_end(start_pos, &end_spanning.end(), items));
174 }
175 }
176 }
177
178 #[doc(hidden)]
179 pub fn expect_name(&mut self) -> ParseResult<&'a str> {
180 match *self.peek() {
181 Spanning {
182 item: Token::Name(_),
183 ..
184 } => Ok(self.next_token()?.map(|token| {
185 if let Token::Name(name) = token {
186 name
187 } else {
188 panic!("Internal parse error in `expect_name`");
189 }
190 })),
191 Spanning {
192 item: Token::EndOfFile,
193 ..
194 } => Err(Spanning::new(
195 self.peek().span,
196 ParseError::UnexpectedEndOfFile,
197 )),
198 _ => Err(self.next_token()?.map(ParseError::unexpected_token)),
199 }
200 }
201}