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.rs36
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!(),
}