use drop_bomb::DropBomb; use self::{ error::SyntaxError, events::{Event, NodeKind}, input::Input, syntax_kind::SyntaxKind, }; use std::cell::Cell; pub mod syntax_kind; #[cfg(test)] mod tests; pub mod error; pub mod events; pub mod grammar; pub mod input; pub mod output; const PARSER_STEP_LIMIT: u32 = 4096; pub struct Parser<'src, 'toks> { input: Input<'src, 'toks>, pos: usize, events: Vec, steps: Cell, } impl<'src, 'toks> Parser<'src, 'toks> { pub fn new(input: Input<'src, 'toks>) -> Self { Self { input, pos: 0, events: Vec::new(), steps: Cell::new(0), } } pub fn finish(self) -> Vec { self.events } pub(crate) fn nth(&self, n: usize) -> SyntaxKind { self.step(); 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.step(); self.input.kind(self.pos) } pub(crate) fn start(&mut self, name: &str) -> Marker { let pos = self.events.len(); self.push_ev(Event::tombstone()); Marker::new(pos, name) } 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) } fn step(&self) { let steps = self.steps.get(); assert!(steps <= PARSER_STEP_LIMIT, "the parser seems stuck..."); self.steps.set(steps + 1); } } pub(crate) struct Marker { pos: usize, bomb: DropBomb, } impl Marker { pub(crate) fn new(pos: usize, name: &str) -> Self { Self { pos, bomb: DropBomb::new(format!("Marker {name} must be completed or abandoned")), } } fn close_node(mut self, p: &mut Parser, kind: NodeKind) -> CompletedMarker { 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(crate) fn complete(self, p: &mut Parser<'_, '_>, kind: SyntaxKind) -> CompletedMarker { self.close_node(p, NodeKind::Syntax(kind)) } pub(crate) fn error(self, p: &mut Parser, kind: SyntaxError) -> CompletedMarker { self.close_node(p, NodeKind::Error(kind)) } 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: NodeKind::Syntax(SyntaxKind::TOMBSTONE), forward_parent: None, }) => (), _ => unreachable!(), } } } } pub(crate) struct CompletedMarker { pos: usize, kind: NodeKind, } impl CompletedMarker { pub(crate) fn precede(self, p: &mut Parser<'_, '_>, 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 } }