1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
//! Events emitted by the Parser which are then constructed into a syntax tree
use std::{mem, ops::Range};
use crate::{
ParserError,
SyntaxKind::{self, *},
TreeSink,
};
/// Events emitted by the Parser, these events are later
/// made into a syntax tree with `process` into TreeSink.
#[derive(Debug, Clone)]
pub enum Event {
/// This event signifies the start of the node.
/// It should be either abandoned (in which case the
/// `kind` is `TOMBSTONE`, and the event is ignored),
/// or completed via a `Finish` event.
///
/// All tokens between a `Start` and a `Finish` would
/// become the children of the respective node.
Start {
kind: SyntaxKind,
start: usize,
forward_parent: Option<u32>,
},
/// Complete the previous `Start` event
Finish {
end: usize,
},
/// Produce a single leaf-element.
/// `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,
range: Range<usize>,
},
MultipleTokens {
amount: u8,
kind: SyntaxKind,
},
}
impl Event {
pub fn tombstone(start: usize) -> Self {
Event::Start {
kind: TOMBSTONE,
forward_parent: None,
start,
}
}
}
/// Generate the syntax tree with the control of events.
#[inline]
pub fn process(sink: &mut impl TreeSink, mut events: Vec<Event>, errors: Vec<ParserError>) {
sink.errors(errors);
let mut forward_parents = Vec::new();
for i in 0..events.len() {
match mem::replace(&mut events[i], Event::tombstone(0)) {
Event::Start {
kind: TOMBSTONE, ..
} => (),
Event::Start {
kind,
forward_parent,
..
} => {
// For events[A, B, C], B is A's forward_parent, C is B's forward_parent,
// in the normal control flow, the parent-child relation: `A -> B -> C`,
// while with the magic forward_parent, it writes: `C <- B <- A`.
// append `A` into parents.
forward_parents.push(kind);
let mut idx = i;
let mut fp = forward_parent;
while let Some(fwd) = fp {
idx += fwd as usize;
// append `A`'s forward_parent `B`
fp = match mem::replace(&mut events[idx], Event::tombstone(0)) {
Event::Start {
kind,
forward_parent,
..
} => {
if kind != TOMBSTONE {
forward_parents.push(kind);
}
forward_parent
}
_ => unreachable!(),
};
// append `B`'s forward_parent `C` in the next stage.
}
for kind in forward_parents.drain(..).rev() {
sink.start_node(kind);
}
}
Event::Finish { .. } => sink.finish_node(),
Event::Token { kind, .. } => {
sink.token(kind);
}
Event::MultipleTokens { amount, kind } => sink.consume_multiple_tokens(amount, kind),
}
}
}