Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/parser/src/parser.rs')
| -rw-r--r-- | crates/parser/src/parser.rs | 36 |
1 files changed, 27 insertions, 9 deletions
diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index 4557078de9..57c501eda2 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -1,6 +1,6 @@ //! See [`Parser`]. -use std::cell::Cell; +use std::{cell::Cell, num::NonZeroU32}; use drop_bomb::DropBomb; @@ -12,6 +12,14 @@ use crate::{ input::Input, }; +/// Build a forward-parent offset. The offset is always ≥ 1 because the +/// forward-parent event is created *after* the event it forwards to, so +/// `NonZeroU32` is always valid here. Panics only on a parser bug. +#[inline] +fn fwd_parent(offset: u32) -> NonZeroU32 { + NonZeroU32::new(offset).expect("forward-parent offset must be non-zero") +} + /// `Parser` struct provides the low-level API for /// navigating through the stream of tokens and /// constructing the parse tree. The actual parsing @@ -25,6 +33,9 @@ pub(crate) struct Parser<'t> { inp: &'t Input, pos: usize, events: Vec<Event>, + /// Side table of error messages. `Event::Error { err }` carries an index + /// into this vec, keeping `Event` itself a flat 8-byte enum. + errors: Vec<String>, steps: Cell<u32>, } @@ -32,11 +43,17 @@ const PARSER_STEP_LIMIT: usize = if cfg!(debug_assertions) { 150_000 } else { 15 impl<'t> Parser<'t> { pub(super) fn new(inp: &'t Input) -> Parser<'t> { - Parser { inp, pos: 0, events: Vec::with_capacity(2 * inp.len()), steps: Cell::new(0) } + Parser { + inp, + pos: 0, + events: Vec::with_capacity(2 * inp.len()), + errors: Vec::new(), + steps: Cell::new(0), + } } - pub(crate) fn finish(self) -> Vec<Event> { - self.events + pub(crate) fn finish(self) -> (Vec<Event>, Vec<String>) { + (self.events, self.errors) } /// Returns the kind of the current token. @@ -206,7 +223,7 @@ impl<'t> Parser<'t> { match &mut self.events[idx] { Event::Start { forward_parent, kind } => { *kind = SyntaxKind::FIELD_EXPR; - *forward_parent = Some(new_marker.pos - marker.pos); + *forward_parent = Some(fwd_parent(new_marker.pos - marker.pos)); } _ => unreachable!(), } @@ -237,8 +254,9 @@ impl<'t> Parser<'t> { /// structured errors with spans and notes, like rustc /// does. pub(crate) fn error<T: Into<String>>(&mut self, message: T) { - let msg = message.into(); - self.push_event(Event::Error { msg }); + let err = self.errors.len() as u32; + self.errors.push(message.into()); + self.push_event(Event::Error { err }); } /// Consume the next token if it is `kind` or emit an error @@ -366,7 +384,7 @@ impl CompletedMarker { let idx = self.start_pos as usize; match &mut p.events[idx] { Event::Start { forward_parent, .. } => { - *forward_parent = Some(new_pos.pos - self.start_pos); + *forward_parent = Some(fwd_parent(new_pos.pos - self.start_pos)); } _ => unreachable!(), } @@ -379,7 +397,7 @@ impl CompletedMarker { let idx = m.pos as usize; match &mut p.events[idx] { Event::Start { forward_parent, .. } => { - *forward_parent = Some(self.start_pos - m.pos); + *forward_parent = Some(fwd_parent(self.start_pos - m.pos)); } _ => unreachable!(), } |