#![forbid(unsafe_op_in_unsafe_fn)]
#![deny(missing_docs)]
#![cfg_attr(feature = "strict_api", deny(unreachable_pub))]
#![cfg_attr(not(feature = "strict_api"), warn(unreachable_pub))]
#![cfg_attr(feature = "strict_docs", deny(missing_docs))]
#![cfg_attr(not(feature = "strict_docs"), allow(missing_docs))]
use core::fmt::{self, Display, Formatter};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParserBackendSelection {
Backend(ParserBackend),
ConflictsRequireGlr,
}
pub const CONFLICTS_REQUIRE_GLR_MESSAGE: &str = "Grammar has conflicts but GLR feature is not enabled. Enable the 'glr' feature in Cargo.toml or use the tree-sitter C runtime.";
impl ParserBackend {
pub const fn select_contract(has_conflicts: bool) -> ParserBackendSelection {
match (cfg!(feature = "glr"), cfg!(feature = "pure-rust")) {
(true, _) => ParserBackendSelection::Backend(Self::GLR),
(false, true) => {
if has_conflicts {
ParserBackendSelection::ConflictsRequireGlr
} else {
ParserBackendSelection::Backend(Self::PureRust)
}
}
_ => ParserBackendSelection::Backend(Self::TreeSitter),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParserBackend {
TreeSitter,
PureRust,
GLR,
}
impl ParserBackend {
pub const fn select(_has_conflicts: bool) -> Self {
match Self::select_contract(_has_conflicts) {
ParserBackendSelection::Backend(backend) => backend,
ParserBackendSelection::ConflictsRequireGlr => {
panic!("{}", CONFLICTS_REQUIRE_GLR_MESSAGE)
}
}
}
pub const fn is_glr(self) -> bool {
matches!(self, Self::GLR)
}
pub const fn is_pure_rust(self) -> bool {
matches!(self, Self::PureRust | Self::GLR)
}
pub const fn name(self) -> &'static str {
match self {
Self::TreeSitter => "tree-sitter C runtime",
Self::PureRust => "pure-Rust LR parser",
Self::GLR => "pure-Rust GLR parser",
}
}
}
impl Display for ParserBackend {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn name_returns_human_readable_string() {
assert_eq!(ParserBackend::TreeSitter.name(), "tree-sitter C runtime");
assert_eq!(ParserBackend::PureRust.name(), "pure-Rust LR parser");
assert_eq!(ParserBackend::GLR.name(), "pure-Rust GLR parser");
}
#[test]
fn display_matches_name() {
for backend in [
ParserBackend::TreeSitter,
ParserBackend::PureRust,
ParserBackend::GLR,
] {
assert_eq!(format!("{backend}"), backend.name());
}
}
#[test]
fn is_glr_only_for_glr() {
assert!(ParserBackend::GLR.is_glr());
assert!(!ParserBackend::PureRust.is_glr());
assert!(!ParserBackend::TreeSitter.is_glr());
}
#[test]
fn is_pure_rust_for_lr_and_glr() {
assert!(ParserBackend::PureRust.is_pure_rust());
assert!(ParserBackend::GLR.is_pure_rust());
assert!(!ParserBackend::TreeSitter.is_pure_rust());
}
#[test]
fn clone_and_eq() {
let a = ParserBackend::GLR;
let b = a;
assert_eq!(a, b);
}
#[test]
fn debug_format() {
let dbg = format!("{:?}", ParserBackend::TreeSitter);
assert_eq!(dbg, "TreeSitter");
}
}