plissken_core/parser/
traits.rs1use crate::error::Result;
7use crate::model::{PythonModule, RustModule};
8use std::path::Path;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum ParserLanguage {
13 Rust,
15 Python,
17}
18
19impl std::fmt::Display for ParserLanguage {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match self {
22 ParserLanguage::Rust => write!(f, "Rust"),
23 ParserLanguage::Python => write!(f, "Python"),
24 }
25 }
26}
27
28#[derive(Debug, Clone)]
33pub enum Module {
34 Rust(RustModule),
36 Python(PythonModule),
38}
39
40impl Module {
41 pub fn path(&self) -> &str {
43 match self {
44 Module::Rust(m) => &m.path,
45 Module::Python(m) => &m.path,
46 }
47 }
48
49 pub fn language(&self) -> ParserLanguage {
51 match self {
52 Module::Rust(_) => ParserLanguage::Rust,
53 Module::Python(_) => ParserLanguage::Python,
54 }
55 }
56
57 pub fn as_rust(&self) -> Option<&RustModule> {
59 match self {
60 Module::Rust(m) => Some(m),
61 Module::Python(_) => None,
62 }
63 }
64
65 pub fn as_python(&self) -> Option<&PythonModule> {
67 match self {
68 Module::Rust(_) => None,
69 Module::Python(m) => Some(m),
70 }
71 }
72
73 pub fn into_rust(self) -> Option<RustModule> {
75 match self {
76 Module::Rust(m) => Some(m),
77 Module::Python(_) => None,
78 }
79 }
80
81 pub fn into_python(self) -> Option<PythonModule> {
83 match self {
84 Module::Rust(_) => None,
85 Module::Python(m) => Some(m),
86 }
87 }
88}
89
90impl From<RustModule> for Module {
91 fn from(m: RustModule) -> Self {
92 Module::Rust(m)
93 }
94}
95
96impl From<PythonModule> for Module {
97 fn from(m: PythonModule) -> Self {
98 Module::Python(m)
99 }
100}
101
102pub trait Parser: Send {
122 fn parse_file(&mut self, path: &Path) -> Result<Module>;
132
133 fn parse_str(&mut self, content: &str, virtual_path: &Path) -> Result<Module>;
146
147 fn language(&self) -> ParserLanguage;
149
150 fn name(&self) -> &'static str;
152
153 fn extensions(&self) -> &'static [&'static str];
155
156 fn can_parse_extension(&self, ext: &str) -> bool {
158 self.extensions()
159 .iter()
160 .any(|e| e.eq_ignore_ascii_case(ext))
161 }
162}
163
164pub fn create_parser(language: ParserLanguage) -> Box<dyn Parser> {
175 match language {
176 ParserLanguage::Rust => Box::new(super::RustParser::new()),
177 ParserLanguage::Python => Box::new(super::PythonParser::new()),
178 }
179}
180
181pub fn parser_for_extension(ext: &str) -> Option<Box<dyn Parser>> {
195 match ext.to_lowercase().as_str() {
196 "rs" => Some(Box::new(super::RustParser::new())),
197 "py" | "pyi" => Some(Box::new(super::PythonParser::new())),
198 _ => None,
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_parser_language_display() {
208 assert_eq!(ParserLanguage::Rust.to_string(), "Rust");
209 assert_eq!(ParserLanguage::Python.to_string(), "Python");
210 }
211
212 #[test]
213 fn test_module_conversions() {
214 let rust_module = RustModule::test("crate::test");
215 let module: Module = rust_module.into();
216
217 assert!(matches!(module.language(), ParserLanguage::Rust));
218 assert!(module.as_rust().is_some());
219 assert!(module.as_python().is_none());
220 }
221
222 #[test]
223 fn test_create_parser() {
224 let rust_parser = create_parser(ParserLanguage::Rust);
225 assert_eq!(rust_parser.language(), ParserLanguage::Rust);
226 assert_eq!(rust_parser.name(), "Rust");
227 assert!(rust_parser.extensions().contains(&"rs"));
228
229 let python_parser = create_parser(ParserLanguage::Python);
230 assert_eq!(python_parser.language(), ParserLanguage::Python);
231 assert_eq!(python_parser.name(), "Python");
232 assert!(python_parser.extensions().contains(&"py"));
233 }
234
235 #[test]
236 fn test_parser_for_extension() {
237 assert!(parser_for_extension("rs").is_some());
238 assert!(parser_for_extension("RS").is_some()); assert!(parser_for_extension("py").is_some());
240 assert!(parser_for_extension("pyi").is_some());
241 assert!(parser_for_extension("js").is_none());
242 assert!(parser_for_extension("").is_none());
243 }
244
245 #[test]
246 fn test_can_parse_extension() {
247 let parser = create_parser(ParserLanguage::Rust);
248 assert!(parser.can_parse_extension("rs"));
249 assert!(parser.can_parse_extension("RS"));
250 assert!(!parser.can_parse_extension("py"));
251 }
252}