use drop_bomb::DropBomb;
use super::{
error::SyntaxError,
event::{Event, NodeKind},
Parser, SyntaxElement,
};
pub struct Marker {
pos: usize,
bomb: DropBomb,
}
impl Marker {
pub(super) fn new(pos: usize, name: &str) -> Self {
Self {
pos,
bomb: DropBomb::new(format!("Marker {name} must be completed or abandoned.")),
}
}
fn close_node<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError>(
mut self,
p: &mut Parser<SyntaxKind, SyntaxErr>,
kind: NodeKind<SyntaxKind, SyntaxErr>,
) -> CompletedMarker<SyntaxKind, SyntaxErr> {
self.bomb.defuse();
match &mut p.events[self.pos] {
Event::Start { kind: slot, .. } => *slot = kind.clone(),
_ => unreachable!(),
}
p.push_ev(Event::Finish);
CompletedMarker {
pos: self.pos,
kind,
}
}
pub fn complete<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError>(
self,
p: &mut Parser<SyntaxKind, SyntaxErr>,
kind: SyntaxKind,
) -> CompletedMarker<SyntaxKind, SyntaxErr> {
self.close_node(p, NodeKind::Syntax(kind))
}
pub fn error<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError>(
self,
p: &mut Parser<SyntaxKind, SyntaxErr>,
kind: SyntaxErr,
) -> CompletedMarker<SyntaxKind, SyntaxErr> {
self.close_node(p, NodeKind::Error(kind))
}
pub fn abandon<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError>(
mut self,
p: &mut Parser<SyntaxKind, SyntaxErr>,
) {
self.bomb.defuse();
if self.pos == p.events.len() - 1 {
match p.events.pop() {
Some(Event::Start {
kind: NodeKind::Tombstone,
forward_parent: None,
}) => (),
_ => unreachable!(),
}
}
}
}
pub struct CompletedMarker<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError> {
pos: usize,
kind: NodeKind<SyntaxKind, SyntaxErr>,
}
impl<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError> CompletedMarker<SyntaxKind, SyntaxErr> {
pub fn precede(self, p: &mut Parser<SyntaxKind, SyntaxErr>, name: &str) -> Marker {
let new_pos = p.start(name);
match &mut p.events[self.pos] {
Event::Start { forward_parent, .. } => {
*forward_parent = Some(new_pos.pos - self.pos);
}
_ => unreachable!(),
}
new_pos
}
}