Introduce drop-bomb

This commit is contained in:
Aleksey Kladov 2018-08-01 11:58:19 +03:00
parent 37e1625f01
commit ecd5da5b0c
3 changed files with 43 additions and 20 deletions

21
src/drop_bomb.rs Normal file
View file

@ -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<Cow<'static, str>>) -> 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)
}
}
}

View file

@ -31,6 +31,7 @@ mod lexer;
mod parser_api; mod parser_api;
mod grammar; mod grammar;
mod parser_impl; mod parser_impl;
mod drop_bomb;
mod syntax_kinds; mod syntax_kinds;
/// Utilities for simple uses of the parser. /// Utilities for simple uses of the parser.

View file

@ -1,6 +1,7 @@
use { use {
parser_impl::ParserImpl, parser_impl::ParserImpl,
SyntaxKind::{self, ERROR}, SyntaxKind::{self, ERROR},
drop_bomb::DropBomb,
}; };
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -76,7 +77,7 @@ impl<'t> Parser<'t> {
/// consumed between the `start` and the corresponding `Marker::complete` /// consumed between the `start` and the corresponding `Marker::complete`
/// belong to the same node. /// belong to the same node.
pub(crate) fn start(&mut self) -> Marker { pub(crate) fn start(&mut self) -> Marker {
Marker(self.0.start()) Marker::new(self.0.start())
} }
/// Advances the parser by one token. /// Advances the parser by one token.
@ -131,31 +132,31 @@ impl<'t> Parser<'t> {
} }
/// See `Parser::start`. /// See `Parser::start`.
pub(crate) struct Marker(u32); pub(crate) struct Marker {
pos: u32,
bomb: DropBomb,
}
impl Marker { 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. /// Finishes the syntax tree node and assigns `kind` to it.
pub(crate) fn complete(self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker { pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
let pos = self.0; self.bomb.defuse();
::std::mem::forget(self); p.0.complete(self.pos, kind);
p.0.complete(pos, kind); CompletedMarker(self.pos)
CompletedMarker(pos)
} }
/// Abandons the syntax tree node. All its children /// Abandons the syntax tree node. All its children
/// are attached to its parent instead. /// are attached to its parent instead.
pub(crate) fn abandon(self, p: &mut Parser) { pub(crate) fn abandon(mut self, p: &mut Parser) {
let pos = self.0; self.bomb.defuse();
::std::mem::forget(self); p.0.abandon(self.pos);
p.0.abandon(pos);
}
}
impl Drop for Marker {
fn drop(&mut self) {
if !::std::thread::panicking() {
panic!("Marker must be either completed or abandoned");
}
} }
} }
@ -170,6 +171,6 @@ impl CompletedMarker {
/// `B` before starting `A`. `precede` allows to do exactly /// `B` before starting `A`. `precede` allows to do exactly
/// that. See also docs about `forward_parent` in `Event::Start`. /// that. See also docs about `forward_parent` in `Event::Start`.
pub(crate) fn precede(self, p: &mut Parser) -> Marker { pub(crate) fn precede(self, p: &mut Parser) -> Marker {
Marker(p.0.precede(self.0)) Marker::new(p.0.precede(self.0))
} }
} }