Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/parser/src/event.rs')
| -rw-r--r-- | crates/parser/src/event.rs | 46 |
1 files changed, 26 insertions, 20 deletions
diff --git a/crates/parser/src/event.rs b/crates/parser/src/event.rs index 5be9cb2a24..9177f4210b 100644 --- a/crates/parser/src/event.rs +++ b/crates/parser/src/event.rs @@ -2,7 +2,7 @@ //! It is intended to be completely decoupled from the //! parser, so as to allow to evolve the tree representation //! and the parser algorithm independently. -use std::mem; +use std::{mem, num::NonZeroU32}; use crate::{ SyntaxKind::{self, *}, @@ -12,6 +12,12 @@ use crate::{ /// `Parser` produces a flat list of `Event`s. /// They are converted to a tree-structure in /// a separate pass, via `TreeBuilder`. +/// +/// Kept to 8 bytes: error messages live in a side table on the `Parser` +/// (the `errors` vec) and `Event::Error` only stores an index into it. +/// `forward_parent` uses `NonZeroU32` so `Option` is niche-optimised away +/// (the offset is always ≥ 1 because the forward parent sits later in the +/// event stream). #[derive(Debug, PartialEq)] pub(crate) enum Event { /// This event signifies the start of the node. @@ -53,10 +59,7 @@ pub(crate) enum Event { /// ``` /// /// See also `CompletedMarker::precede`. - Start { - kind: SyntaxKind, - forward_parent: Option<u32>, - }, + Start { kind: SyntaxKind, forward_parent: Option<NonZeroU32> }, /// Complete the previous `Start` event Finish, @@ -65,20 +68,14 @@ pub(crate) enum Event { /// `n_raw_tokens` is used to glue complex contextual tokens. /// For example, lexer tokenizes `>>` as `>`, `>`, and /// `n_raw_tokens = 2` is used to produced a single `>>`. - Token { - kind: SyntaxKind, - n_raw_tokens: u8, - }, + Token { kind: SyntaxKind, n_raw_tokens: u8 }, /// When we parse `foo.0.0` or `foo. 0. 0` the lexer will hand us a float literal /// instead of an integer literal followed by a dot as the lexer has no contextual knowledge. /// This event instructs whatever consumes the events to split the float literal into /// the corresponding parts. - FloatSplitHack { - ends_in_dot: bool, - }, - Error { - msg: String, - }, + FloatSplitHack { ends_in_dot: bool }, + /// Index into the parser's side `errors` vec. + Error { err: u32 }, } impl Event { @@ -87,9 +84,12 @@ impl Event { } } -/// Generate the syntax tree with the control of events. -pub(super) fn process(mut events: Vec<Event>) -> Output { - let mut res = Output::default(); +/// Generate the syntax tree with the control of events. `errors` is the +/// side table of error messages built up alongside the `events` stream. +pub(super) fn process(mut events: Vec<Event>, mut errors: Vec<String>) -> Output { + // Each event becomes roughly one u32 in Output, so preallocate to avoid + // the amortized grow-one churn we used to see in Output::enter_node. + let mut res = Output::with_event_capacity(events.len()); let mut forward_parents = Vec::new(); for i in 0..events.len() { @@ -104,7 +104,7 @@ pub(super) fn process(mut events: Vec<Event>) -> Output { let mut idx = i; let mut fp = forward_parent; while let Some(fwd) = fp { - idx += fwd as usize; + idx += fwd.get() as usize; // append `A`'s forward_parent `B` fp = match mem::replace(&mut events[idx], Event::tombstone()) { Event::Start { kind, forward_parent } => { @@ -131,7 +131,13 @@ pub(super) fn process(mut events: Vec<Event>) -> Output { let ev = mem::replace(&mut events[i + 1], Event::tombstone()); assert!(matches!(ev, Event::Finish), "{ev:?}"); } - Event::Error { msg } => res.error(msg), + Event::Error { err } => { + // Move the string out of the side table; each index is visited + // exactly once, so swapping with an empty String is cheap and + // avoids any clone. + let msg = mem::take(&mut errors[err as usize]); + res.error(msg); + } } } |