1use pepl_lexer::token::{Token, TokenKind};
4use pepl_types::{CompileErrors, ErrorCode, PeplError, SourceFile, Span};
5
6pub struct Parser<'src> {
11 tokens: Vec<Token>,
13 pos: usize,
15 source_file: &'src SourceFile,
17 file_name: String,
19 errors: CompileErrors,
21 pub(crate) lambda_depth: u32,
23 pub(crate) record_depth: u32,
25 pub(crate) expr_depth: u32,
27 pub(crate) for_depth: u32,
29}
30
31pub struct ParseResult {
33 pub program: Option<pepl_types::ast::Program>,
34 pub errors: CompileErrors,
35}
36
37impl<'src> Parser<'src> {
38 pub fn new(tokens: Vec<Token>, source_file: &'src SourceFile) -> Self {
40 Self {
41 tokens,
42 pos: 0,
43 file_name: source_file.name.clone(),
44 source_file,
45 errors: CompileErrors::empty(),
46 lambda_depth: 0,
47 record_depth: 0,
48 expr_depth: 0,
49 for_depth: 0,
50 }
51 }
52
53 pub(crate) fn peek(&self) -> &Token {
57 self.tokens.get(self.pos).unwrap_or_else(|| {
58 self.tokens
59 .last()
60 .expect("token stream should end with Eof")
61 })
62 }
63
64 pub(crate) fn peek_kind(&self) -> &TokenKind {
66 &self.peek().kind
67 }
68
69 pub(crate) fn advance(&mut self) -> Token {
71 let token = self.peek().clone();
72 if self.pos < self.tokens.len() {
73 self.pos += 1;
74 }
75 token
76 }
77
78 pub(crate) fn previous_span(&self) -> Span {
80 if self.pos > 0 {
81 self.tokens[self.pos - 1].span
82 } else {
83 Span::point(1, 1)
84 }
85 }
86
87 pub(crate) fn current_span(&self) -> Span {
89 self.peek().span
90 }
91
92 pub(crate) fn at_end(&self) -> bool {
94 matches!(self.peek_kind(), TokenKind::Eof)
95 }
96
97 #[allow(dead_code)]
99 pub(crate) fn check(&self, kind: &TokenKind) -> bool {
100 std::mem::discriminant(self.peek_kind()) == std::mem::discriminant(kind)
101 }
102
103 pub(crate) fn check_exact(&self, kind: &TokenKind) -> bool {
105 self.peek_kind() == kind
106 }
107
108 pub(crate) fn eat(&mut self, kind: &TokenKind) -> bool {
110 if self.check_exact(kind) {
111 self.advance();
112 true
113 } else {
114 false
115 }
116 }
117
118 pub(crate) fn look_ahead(&self, n: usize) -> &TokenKind {
120 let idx = self.pos + n;
121 self.tokens
122 .get(idx)
123 .map(|t| &t.kind)
124 .unwrap_or(&TokenKind::Eof)
125 }
126
127 pub(crate) fn skip_newlines(&mut self) {
131 while self.check_exact(&TokenKind::Newline) {
132 self.advance();
133 }
134 }
135
136 pub(crate) fn expect_newline_or_eof(&mut self) {
138 if self.at_end() {
139 return;
140 }
141 if self.check_exact(&TokenKind::Newline) {
142 self.advance();
143 self.skip_newlines();
144 } else if !self.check_exact(&TokenKind::RBrace) {
145 self.error_at_current(
147 ErrorCode::UNEXPECTED_TOKEN,
148 format!("expected newline, got '{}'", self.peek_kind()),
149 );
150 }
151 }
152
153 pub(crate) fn expect(&mut self, expected: &TokenKind) -> Option<Token> {
157 if self.check_exact(expected) {
158 Some(self.advance())
159 } else {
160 self.error_at_current(
161 ErrorCode::UNEXPECTED_TOKEN,
162 format!("expected '{}', got '{}'", expected, self.peek_kind()),
163 );
164 None
165 }
166 }
167
168 pub(crate) fn expect_identifier(&mut self) -> Option<pepl_types::ast::Ident> {
170 match self.peek_kind().clone() {
171 TokenKind::Identifier(name) => {
172 let span = self.advance().span;
173 Some(pepl_types::ast::Ident::new(name, span))
174 }
175 _ => {
176 self.error_at_current(
177 ErrorCode::UNEXPECTED_TOKEN,
178 format!("expected identifier, got '{}'", self.peek_kind()),
179 );
180 None
181 }
182 }
183 }
184
185 pub(crate) fn expect_field_name(&mut self) -> Option<pepl_types::ast::Ident> {
193 let kind = self.peek_kind().clone();
194 match &kind {
195 TokenKind::Identifier(name) => {
196 let name = name.clone();
197 let span = self.advance().span;
198 Some(pepl_types::ast::Ident::new(name, span))
199 }
200 _ if kind.is_keyword() => {
201 let name = kind.to_string();
202 let span = self.advance().span;
203 Some(pepl_types::ast::Ident::new(name, span))
204 }
205 _ => {
206 self.error_at_current(
207 ErrorCode::UNEXPECTED_TOKEN,
208 format!("expected field name, got '{}'", self.peek_kind()),
209 );
210 None
211 }
212 }
213 }
214
215 pub(crate) fn expect_ident_or_module_name(&mut self) -> Option<pepl_types::ast::Ident> {
219 let kind = self.peek_kind().clone();
220 match &kind {
221 TokenKind::Identifier(name) => {
222 let name = name.clone();
223 let span = self.advance().span;
224 Some(pepl_types::ast::Ident::new(name, span))
225 }
226 TokenKind::Core
228 | TokenKind::Math
229 | TokenKind::Record
230 | TokenKind::Time
231 | TokenKind::Convert
232 | TokenKind::Json
233 | TokenKind::Timer
234 | TokenKind::Http
235 | TokenKind::Storage
236 | TokenKind::Location
237 | TokenKind::Notifications
238 | TokenKind::Clipboard
239 | TokenKind::Share
240 | TokenKind::KwString
242 | TokenKind::KwList
243 | TokenKind::KwColor => {
244 let name = kind.to_string();
245 let span = self.advance().span;
246 Some(pepl_types::ast::Ident::new(name, span))
247 }
248 _ => {
249 self.error_at_current(
250 ErrorCode::UNEXPECTED_TOKEN,
251 format!("expected identifier, got '{}'", self.peek_kind()),
252 );
253 None
254 }
255 }
256 }
257
258 pub(crate) fn expect_string_literal(&mut self) -> Option<String> {
260 match self.peek_kind().clone() {
261 TokenKind::StringLiteral(s) => {
262 self.advance();
263 Some(s)
264 }
265 _ => {
266 self.error_at_current(
267 ErrorCode::UNEXPECTED_TOKEN,
268 format!("expected string literal, got '{}'", self.peek_kind()),
269 );
270 None
271 }
272 }
273 }
274
275 pub(crate) fn expect_upper_identifier(&mut self) -> Option<pepl_types::ast::Ident> {
277 match self.peek_kind().clone() {
278 TokenKind::Identifier(ref name)
279 if name.starts_with(|c: char| c.is_ascii_uppercase()) =>
280 {
281 let name = name.clone();
282 let span = self.advance().span;
283 Some(pepl_types::ast::Ident::new(name, span))
284 }
285 _ => {
286 self.error_at_current(
287 ErrorCode::UNEXPECTED_TOKEN,
288 format!("expected PascalCase identifier, got '{}'", self.peek_kind()),
289 );
290 None
291 }
292 }
293 }
294
295 pub(crate) fn eat_comma(&mut self) -> bool {
297 self.eat(&TokenKind::Comma)
298 }
299
300 pub(crate) fn expect_member_name(&mut self) -> Option<pepl_types::ast::Ident> {
303 let kind = self.peek_kind().clone();
304 match &kind {
305 TokenKind::Identifier(name) => {
306 let name = name.clone();
307 let span = self.advance().span;
308 Some(pepl_types::ast::Ident::new(name, span))
309 }
310 TokenKind::Set => {
312 let span = self.advance().span;
313 Some(pepl_types::ast::Ident::new("set", span))
314 }
315 TokenKind::Type => {
316 let span = self.advance().span;
317 Some(pepl_types::ast::Ident::new("type", span))
318 }
319 TokenKind::Match => {
320 let span = self.advance().span;
321 Some(pepl_types::ast::Ident::new("match", span))
322 }
323 TokenKind::Update => {
324 let span = self.advance().span;
325 Some(pepl_types::ast::Ident::new("update", span))
326 }
327 _ => {
328 self.error_at_current(
329 ErrorCode::UNEXPECTED_TOKEN,
330 format!("expected identifier, got '{}'", self.peek_kind()),
331 );
332 None
333 }
334 }
335 }
336
337 pub(crate) fn error_at_current(&mut self, code: ErrorCode, message: impl Into<String>) {
341 let span = self.current_span();
342 self.error_at(code, message, span);
343 }
344
345 pub(crate) fn error_at(&mut self, code: ErrorCode, message: impl Into<String>, span: Span) {
347 let source_line = self
348 .source_file
349 .line(span.start_line)
350 .unwrap_or("")
351 .to_string();
352 let error = PeplError::new(&self.file_name, code, message, span, source_line);
353 self.errors.push_error(error);
354 }
355
356 pub(crate) fn too_many_errors(&self) -> bool {
358 self.errors.has_errors() && self.errors.total_errors >= pepl_types::MAX_ERRORS
359 }
360
361 pub(crate) fn synchronize(&mut self) {
366 while !self.at_end() {
367 if self.check_exact(&TokenKind::Newline) {
369 self.advance();
370 self.skip_newlines();
371 return;
372 }
373 match self.peek_kind() {
375 TokenKind::Space
376 | TokenKind::State
377 | TokenKind::Action
378 | TokenKind::View
379 | TokenKind::Set
380 | TokenKind::Let
381 | TokenKind::If
382 | TokenKind::For
383 | TokenKind::Match
384 | TokenKind::Return
385 | TokenKind::Invariant
386 | TokenKind::Capabilities
387 | TokenKind::Credentials
388 | TokenKind::Derived
389 | TokenKind::Tests
390 | TokenKind::Test
391 | TokenKind::Assert
392 | TokenKind::Type
393 | TokenKind::Update
394 | TokenKind::HandleEvent
395 | TokenKind::RBrace => return,
396 _ => {
397 self.advance();
398 }
399 }
400 }
401 }
402
403 pub fn parse(mut self) -> ParseResult {
407 self.skip_newlines();
408 let program = self.parse_program();
409 ParseResult {
410 program,
411 errors: self.errors,
412 }
413 }
414}