diff --git a/src/drop_bomb.rs b/src/drop_bomb.rs new file mode 100644 index 0000000000..750904a013 --- /dev/null +++ b/src/drop_bomb.rs @@ -0,0 +1,21 @@ +use std::borrow::Cow; + +pub struct DropBomb { + msg: Cow<'static, str>, + defused: bool, +} + +impl DropBomb { + pub fn new(msg: impl Into>) -> DropBomb { + DropBomb { msg: msg.into(), defused: false } + } + pub fn defuse(&mut self) { self.defused = true } +} + +impl Drop for DropBomb { + fn drop(&mut self) { + if !self.defused && !::std::thread::panicking() { + panic!("{}", self.msg) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 1cd45690a4..d9572912cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ mod lexer; mod parser_api; mod grammar; mod parser_impl; +mod drop_bomb; mod syntax_kinds; /// Utilities for simple uses of the parser. diff --git a/src/parser_api.rs b/src/parser_api.rs index d12f773b2c..3cad91976c 100644 --- a/src/parser_api.rs +++ b/src/parser_api.rs @@ -1,6 +1,7 @@ use { parser_impl::ParserImpl, SyntaxKind::{self, ERROR}, + drop_bomb::DropBomb, }; #[derive(Clone, Copy)] @@ -76,7 +77,7 @@ impl<'t> Parser<'t> { /// consumed between the `start` and the corresponding `Marker::complete` /// belong to the same node. pub(crate) fn start(&mut self) -> Marker { - Marker(self.0.start()) + Marker::new(self.0.start()) } /// Advances the parser by one token. @@ -131,31 +132,31 @@ impl<'t> Parser<'t> { } /// See `Parser::start`. -pub(crate) struct Marker(u32); +pub(crate) struct Marker { + pos: u32, + bomb: DropBomb, +} impl Marker { + fn new(pos: u32) -> Marker { + Marker { + pos, + bomb: DropBomb::new("Marker must be either completed or abandoned") + } + } + /// Finishes the syntax tree node and assigns `kind` to it. - pub(crate) fn complete(self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker { - let pos = self.0; - ::std::mem::forget(self); - p.0.complete(pos, kind); - CompletedMarker(pos) + pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker { + self.bomb.defuse(); + p.0.complete(self.pos, kind); + CompletedMarker(self.pos) } /// Abandons the syntax tree node. All its children /// are attached to its parent instead. - pub(crate) fn abandon(self, p: &mut Parser) { - let pos = self.0; - ::std::mem::forget(self); - p.0.abandon(pos); - } -} - -impl Drop for Marker { - fn drop(&mut self) { - if !::std::thread::panicking() { - panic!("Marker must be either completed or abandoned"); - } + pub(crate) fn abandon(mut self, p: &mut Parser) { + self.bomb.defuse(); + p.0.abandon(self.pos); } } @@ -170,6 +171,6 @@ impl CompletedMarker { /// `B` before starting `A`. `precede` allows to do exactly /// that. See also docs about `forward_parent` in `Event::Start`. pub(crate) fn precede(self, p: &mut Parser) -> Marker { - Marker(p.0.precede(self.0)) + Marker::new(p.0.precede(self.0)) } }