use drop_bomb::DropBomb; use self::{error::SyntaxError, events::Event, input::Input, syntax_kind::SyntaxKind}; pub mod syntax_kind; #[cfg(test)] mod tests; pub mod error; pub mod events; pub mod grammar; pub mod input; pub mod output; pub struct Parser<'src, 'toks> { input: Input<'src, 'toks>, pos: usize, events: Vec, errors: Vec, } impl<'src, 'toks> Parser<'src, 'toks> { pub fn new(input: Input<'src, 'toks>) -> Self { Self { input, pos: 0, events: Vec::new(), errors: Vec::new(), } } pub fn finish(self) -> (Vec, Vec) { (self.events, self.errors) } pub(crate) fn nth(&self, n: usize) -> SyntaxKind { self.input.kind(self.pos + n) } pub fn eat_succeeding_ws(&mut self) { self.push_ev(Event::Eat { count: self.input.meaningless_tail_len(), }); } pub(crate) fn current(&self) -> SyntaxKind { self.input.kind(self.pos) } pub(crate) fn start(&mut self) -> Marker { let pos = self.events.len(); self.push_ev(Event::tombstone()); Marker::new(pos) } pub(crate) fn at(&self, kind: SyntaxKind) -> bool { self.nth_at(0, kind) } pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool { if !self.at(kind) { return false; } self.do_bump(); true } pub(crate) fn nth_at(&self, n: usize, kind: SyntaxKind) -> bool { self.nth(n) == kind } fn do_bump(&mut self) { self.push_ev(Event::Eat { count: self.input.preceding_meaningless(self.pos), }); self.pos += 1; } fn push_ev(&mut self, event: Event) { self.events.push(event) } } pub(crate) struct Marker { pos: usize, bomb: DropBomb, } impl Marker { pub(crate) fn new(pos: usize) -> Self { Self { pos, bomb: DropBomb::new("Marker must be completed or abandoned"), } } pub(crate) fn complete(mut self, p: &mut Parser<'_, '_>, kind: SyntaxKind) -> CompletedMarker { self.bomb.defuse(); match &mut p.events[self.pos] { Event::Start { kind: slot, .. } => *slot = kind, _ => unreachable!(), } p.push_ev(Event::Finish); CompletedMarker { pos: self.pos, kind, } } pub(crate) fn complete_err(mut self, p: &mut Parser, kind: SyntaxError) -> CompletedMarker { p.errors.push(kind); self.complete(p, SyntaxKind::PARSE_ERR) } pub(crate) fn abandon(mut self, p: &mut Parser<'_, '_>) { self.bomb.defuse(); if self.pos == p.events.len() - 1 { match p.events.pop() { Some(Event::Start { kind: SyntaxKind::TOMBSTONE, forward_parent: None, }) => (), _ => unreachable!(), } } } } pub(crate) struct CompletedMarker { pos: usize, kind: SyntaxKind, } impl CompletedMarker { pub(crate) fn precede(self, p: &mut Parser<'_, '_>) -> Marker { let new_pos = p.start(); match &mut p.events[self.pos] { Event::Start { forward_parent, .. } => { *forward_parent = Some(new_pos.pos - self.pos); } _ => unreachable!(), } new_pos } }