pomsky_syntax/parse/
parser.rs1use std::str::FromStr;
2
3use crate::{
4 diagnose::{NumberError, ParseDiagnostic, ParseError, ParseErrorKind as PEK, ParseWarning},
5 exprs::*,
6 lexer::{tokenize, Token},
7 Span,
8};
9
10pub fn parse(source: &str, recursion: u32) -> (Option<Rule<'_>>, Vec<ParseDiagnostic>) {
17 let tokens = tokenize(source);
18
19 let mut errors = Vec::new();
20 for &(t, span) in &tokens {
21 match t {
22 Token::Error => errors.push((span, None)),
23 Token::ErrorMsg(m) => errors.push((span, Some(m))),
24 _ => {}
25 }
26 }
27
28 if !errors.is_empty() {
29 let errors = errors
30 .into_iter()
31 .map(|(span, msg)| {
32 msg.map_or(PEK::UnknownToken, PEK::LexErrorWithMessage).at(span).into()
33 })
34 .collect::<Vec<_>>();
35
36 return (None, errors);
37 }
38
39 let mut parser = Parser {
40 source,
41 tokens: tokens.into_boxed_slice(),
42 offset: 0,
43 warnings: Vec::new(),
44 recursion,
45 };
46
47 let rule = match parser.parse_modified() {
48 Ok(rule) => rule,
49 Err(err) => {
50 let mut diagnostics = vec![err.into()];
51 diagnostics.extend(parser.warnings);
52 return (None, diagnostics);
53 }
54 };
55 if parser.is_empty() {
56 (Some(rule), parser.warnings)
57 } else {
58 let mut diagnostics = vec![PEK::LeftoverTokens.at(parser.span()).into()];
59 diagnostics.extend(parser.warnings);
60 (None, diagnostics)
61 }
62}
63
64type PResult<T> = Result<T, ParseError>;
65
66pub(super) struct Parser<'i> {
67 source: &'i str,
68 tokens: Box<[(Token, Span)]>,
69 offset: usize,
70 warnings: Vec<ParseDiagnostic>,
71 recursion: u32,
72}
73
74impl<'i> Parser<'i> {
76 pub(super) fn is_empty(&self) -> bool {
77 self.tokens.len() == self.offset
78 }
79
80 pub(super) fn source_at(&self, span: Span) -> &'i str {
81 &self.source[span.range_unchecked()]
82 }
83
84 pub(super) fn peek(&self) -> Option<(Token, &'i str)> {
85 self.tokens.get(self.offset).map(|&(t, span)| (t, self.source_at(span)))
86 }
87
88 pub(super) fn peek_pair(&self) -> Option<(Token, Span)> {
89 self.tokens.get(self.offset).copied()
90 }
91
92 pub(super) fn span(&self) -> Span {
94 self.tokens
95 .get(self.offset)
96 .map_or_else(|| Span::new(self.source.len(), self.source.len()), |&(_, s)| s)
97 }
98
99 pub(super) fn last_span(&self) -> Span {
101 self.tokens[self.offset - 1].1
102 }
103
104 pub(super) fn advance(&mut self) {
105 self.offset += 1;
106 }
107
108 pub(super) fn recursion_start(&mut self) -> PResult<()> {
109 self.recursion =
110 self.recursion.checked_sub(1).ok_or_else(|| PEK::RecursionLimit.at(self.span()))?;
111 Ok(())
112 }
113
114 pub(super) fn recursion_end(&mut self) {
115 self.recursion += 1;
116 }
117
118 pub(super) fn add_warning(&mut self, warning: ParseWarning) {
119 self.warnings.push(warning.into());
120 }
121
122 pub(super) fn is(&mut self, token: Token) -> bool {
123 matches!(self.peek_pair(), Some((t, _)) if t == token)
124 }
125
126 pub(super) fn consume(&mut self, token: Token) -> bool {
127 match self.peek_pair() {
128 Some((t, _)) if t == token => {
129 self.offset += 1;
130 true
131 }
132 _ => false,
133 }
134 }
135
136 pub(super) fn consume_as(&mut self, token: Token) -> Option<&'i str> {
137 match self.peek_pair() {
138 Some((t, span)) if t == token => {
139 self.offset += 1;
140 Some(self.source_at(span))
141 }
142 _ => None,
143 }
144 }
145
146 pub(super) fn consume_reserved(&mut self, reserved: &str) -> bool {
147 match self.peek_pair() {
148 Some((Token::ReservedName, s)) if self.source_at(s) == reserved => {
149 self.offset += 1;
150 true
151 }
152 _ => false,
153 }
154 }
155
156 pub(super) fn consume_contextual_keyword(&mut self, keyword: &str) -> bool {
157 match self.peek_pair() {
158 Some((Token::Identifier, s)) if self.source_at(s) == keyword => {
159 self.offset += 1;
160 true
161 }
162 _ => false,
163 }
164 }
165
166 pub(super) fn consume_number<T: FromStr + PartialOrd>(&mut self, max: T) -> PResult<Option<T>> {
167 match self.peek_pair() {
168 Some((Token::Number, span)) => {
169 let n = str::parse(self.source_at(span))
170 .ok()
171 .and_then(|n| if n > max { None } else { Some(n) })
172 .ok_or_else(|| PEK::Number(NumberError::TooLarge).at(span))?;
173 self.offset += 1;
174 Ok(Some(n))
175 }
176 _ => Ok(None),
177 }
178 }
179
180 pub(super) fn expect(&mut self, token: Token) -> PResult<()> {
181 match self.peek_pair() {
182 Some((t, _)) if t == token => {
183 self.offset += 1;
184 Ok(())
185 }
186 _ => Err(PEK::ExpectedToken(token).at(self.span())),
187 }
188 }
189
190 pub(super) fn expect_as(&mut self, token: Token) -> PResult<&'i str> {
191 match self.peek_pair() {
192 Some((t, span)) if t == token => {
193 self.offset += 1;
194 Ok(self.source_at(span))
195 }
196 _ => Err(PEK::ExpectedToken(token).at(self.span())),
197 }
198 }
199
200 pub(super) fn expect_number<T: FromStr>(&mut self) -> PResult<T> {
201 match self.peek_pair() {
202 Some((Token::Number, span)) => {
203 let n = str::parse(self.source_at(span))
204 .map_err(|_| PEK::Number(NumberError::TooLarge).at(span))?;
205 self.offset += 1;
206 Ok(n)
207 }
208 _ => Err(PEK::ExpectedToken(Token::Number).at(self.span())),
209 }
210 }
211}