adze_parser_backend_core/
lib.rs1#![forbid(unsafe_op_in_unsafe_fn)]
4#![deny(missing_docs)]
5#![cfg_attr(feature = "strict_api", deny(unreachable_pub))]
6#![cfg_attr(not(feature = "strict_api"), warn(unreachable_pub))]
7#![cfg_attr(feature = "strict_docs", deny(missing_docs))]
8#![cfg_attr(not(feature = "strict_docs"), allow(missing_docs))]
9
10use core::fmt::{self, Display, Formatter};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum ParserBackendSelection {
18 Backend(ParserBackend),
20 ConflictsRequireGlr,
22}
23
24pub 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.";
26
27impl ParserBackend {
28 pub const fn select_contract(has_conflicts: bool) -> ParserBackendSelection {
32 match (cfg!(feature = "glr"), cfg!(feature = "pure-rust")) {
33 (true, _) => ParserBackendSelection::Backend(Self::GLR),
34 (false, true) => {
35 if has_conflicts {
36 ParserBackendSelection::ConflictsRequireGlr
37 } else {
38 ParserBackendSelection::Backend(Self::PureRust)
39 }
40 }
41 _ => ParserBackendSelection::Backend(Self::TreeSitter),
42 }
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum ParserBackend {
60 TreeSitter,
62 PureRust,
64 GLR,
66}
67
68impl ParserBackend {
69 pub const fn select(_has_conflicts: bool) -> Self {
77 match Self::select_contract(_has_conflicts) {
78 ParserBackendSelection::Backend(backend) => backend,
79 ParserBackendSelection::ConflictsRequireGlr => {
80 panic!("{}", CONFLICTS_REQUIRE_GLR_MESSAGE)
81 }
82 }
83 }
84
85 pub const fn is_glr(self) -> bool {
87 matches!(self, Self::GLR)
88 }
89
90 pub const fn is_pure_rust(self) -> bool {
92 matches!(self, Self::PureRust | Self::GLR)
93 }
94
95 pub const fn name(self) -> &'static str {
97 match self {
98 Self::TreeSitter => "tree-sitter C runtime",
99 Self::PureRust => "pure-Rust LR parser",
100 Self::GLR => "pure-Rust GLR parser",
101 }
102 }
103}
104
105impl Display for ParserBackend {
106 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
107 write!(f, "{}", self.name())
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn name_returns_human_readable_string() {
117 assert_eq!(ParserBackend::TreeSitter.name(), "tree-sitter C runtime");
118 assert_eq!(ParserBackend::PureRust.name(), "pure-Rust LR parser");
119 assert_eq!(ParserBackend::GLR.name(), "pure-Rust GLR parser");
120 }
121
122 #[test]
123 fn display_matches_name() {
124 for backend in [
125 ParserBackend::TreeSitter,
126 ParserBackend::PureRust,
127 ParserBackend::GLR,
128 ] {
129 assert_eq!(format!("{backend}"), backend.name());
130 }
131 }
132
133 #[test]
134 fn is_glr_only_for_glr() {
135 assert!(ParserBackend::GLR.is_glr());
136 assert!(!ParserBackend::PureRust.is_glr());
137 assert!(!ParserBackend::TreeSitter.is_glr());
138 }
139
140 #[test]
141 fn is_pure_rust_for_lr_and_glr() {
142 assert!(ParserBackend::PureRust.is_pure_rust());
143 assert!(ParserBackend::GLR.is_pure_rust());
144 assert!(!ParserBackend::TreeSitter.is_pure_rust());
145 }
146
147 #[test]
148 fn clone_and_eq() {
149 let a = ParserBackend::GLR;
150 let b = a;
151 assert_eq!(a, b);
152 }
153
154 #[test]
155 fn debug_format() {
156 let dbg = format!("{:?}", ParserBackend::TreeSitter);
157 assert_eq!(dbg, "TreeSitter");
158 }
159}